<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>yoncho`s blog</title>
    <link>https://yonghyn.tistory.com/</link>
    <description>나를 기록합니다. 
성장하기 위해 기록합니다.
경험을 기록합니다.</description>
    <language>ko</language>
    <pubDate>Mon, 11 May 2026 06:49:58 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>욘초</managingEditor>
    <image>
      <title>yoncho`s blog</title>
      <url>https://tistory1.daumcdn.net/tistory/5524583/attach/3a8daa6bd54042e288e70c224c873a9e</url>
      <link>https://yonghyn.tistory.com</link>
    </image>
    <item>
      <title>나의 두 번째 직장, 글로벌 철강 기업의 IT계열사 : 포스코DX</title>
      <link>https://yonghyn.tistory.com/99</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b36zWe/dJMcagqHT8b/u14YOIre5WkvcZIPmOAlk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b36zWe/dJMcagqHT8b/u14YOIre5WkvcZIPmOAlk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b36zWe/dJMcagqHT8b/u14YOIre5WkvcZIPmOAlk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb36zWe%2FdJMcagqHT8b%2Fu14YOIre5WkvcZIPmOAlk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;667&quot; height=&quot;235&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;444&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 직장으로 포스코DX에 입사하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 직장 (아우토크립트)에서 'SecurityFuzzer'를 마무리하고 다음 단계를 넘어갈 때쯤..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어디 합격을 하지 않은 상황에서 퇴사 의사를 밝혔다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 직장은 스타트업이였고, 체계라든지 개발 환경에 대한 규칙이라든지.. 틀이라는게 없었기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엄청 자유롭게 개발했지만 한번쯤은 대기업에서의 업무 프로세스 및 체계를 배워보고 싶은 마음이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그게 'SecurityFuzzer'를 마무리하고 난 시점이 제일 좋은 준비 시기라고 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;퇴사 의사를 밝혔지만 당시 팀장님이 '다른데 합격하기 전까지는 다녀라' 라고 하셔서, 간단한 업무를 수행하며&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 곳을 알아봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 알아본게 현 직장이였고, 첫 직장을 퇴사하고 별도의 교육 및 프로젝트를 진행하는 6개월 과정을 거친 후&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'24년 02월 19일에 입사했다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근무지는 '포스코 센터 (강남)'였고, 1500억 대규모 프로젝트 (마케팅DX)에 투입되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자취방에서 회사가 가까워서 너무 좋았다. 도어 투 도어로 40분!!!!! (美친!!)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 대규모 프로젝트여서 경험 쌓기도 좋을 것 같았다.. (실제로 너무 많이 힘들었지만..그래도 많은 부분들을 경험...했다...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'25년 11월이 본가동이지만, 내가 속한 파트의 MIH는 '25년 02월 선가동을 해야해서 '24년 10월부터 무지막지하게 바빳다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선가동 직전 1월부터는 야근은 기본, 밤샘 작업도 했는데. PL밑에 실무 개발자가 나 혼자라 많이 힘들었고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안나던 코피도 하루에 2번씩 나며 건강과 안색이 많이 안좋아졌다 ㅠ.ㅜ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MIH는 Bloomberg, S&amp;amp;P Global, CRU, MySteel 등 다양한 지표 제공처와의 계약과 API 활용 등에 있어서 줌미팅을 자주 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히, 기억에 남는건 MySteel과 Bloomberg 사이에 껴서 핑퐁핑퐁을 5G게 하며 나만 피가 잔뜩 말리고 힘들었는데..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잊을 수 가 없다...한쪽(Bloomberg)에는 영어로.. 다른 한쪽(MySteel)에는 중국어로 메일을 보냈다;;;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(핑퐁 횟수만 10회가 넘어갔으며, 결국엔 MySteel과 추가 계약을 해서 별도 API를 연결시켰다..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 GPT를 기반으로 뉴스 분석 Agent를 개발했는데.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 Prompt의 존재와 어떻게 설정을해야 GPT가 잘 알아먹는지 .. 다양한 방법을 시도해보며 고생한 경험이 기억에 남는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 분류 목적에 맞게 GPT Prompt와 Logic으로 설정해가며 가중치를 얼만큼 설정해야 잘 분류하는지 다양한 시도 과정이&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재미있었다. (이게 된다고? 왜??)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MIH 선가동 이후 후임도 들어왔다. (내가 그렇게 인력 충원해달라고 떼를 쓰며.. 요청했는데.. 드디어...!!)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 전담했던 개발 업무들을 하나씩 인수인계해주며 다양한 시도 과정들을 공유했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나도 누군가한테 배워야하는 입장이라 내가 말하는게 항상 옳은게 아니니 ... 찾아보고 더 나은 방법이 있으면 공유해달라고 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외에도 외부 컨설턴트(커니/ 딜로이트) 선생님들이 만든 ML 모델들을 인수인계 받고 운영하며 개선시켰는데.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유능한 선생님들과 함께 일할 수 있는 좋은 경험이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마케팅DX 프로젝트가 끝이나고 나는 '25.12.16부 AX융합연구소 AX기술개발그룹으로 발령이 났고...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'26.01.09부 퇴사(의원 면직)하게 되었다. __사유: 타사 전직__&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 회사를 다니며 좋았던 점은..&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;첫 번째로 '입사 동기'가 있었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;나를 제외한 18명의 입사 동기가 있다. 6개월간 교육과정과 프로젝트를 같이 하며 친해진 동기들!!&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;(여행 계모임도 하며 1년에 1~2번 같이 여행도 간다)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;입사 시기가 한달 정도 차이나는 공채 동기들도 있다!!&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;(같이 스쿠버 다이빙 동아리도 하고, 그룹 입문 교육도 같이가고!! 입사 동기라고 생각하며 지낸다)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;두 번째로는 '사수'가 있었다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;내가 '스승님'이라고 부르는 멘토님이 계셨고, 7년차이시지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;과장이셨다. (능력....무엇??)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;신입 OJT를 진행해주시며 적당한 코칭과 스스로 해볼 시간을 주시며 발표 ppt도 챙겨주셨다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;장난도 자주 치고 나랑 둘째(공채)를 많이 아껴주셨다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;특히, AX융합연구소로 전입할 수 있게 연결 다리를 놓아주시고 항상 응원해주셨다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;현재는 통신3사 중 한 곳으로 이직하셨는데. 스승님이 성공해서 너무 좋다!!&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;세 번째로는 '재미있는 고객'이 있었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;우리(POSCO DX)한텐 포스코가 '고객(현업)' 이다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;개발직군이 아닌데... IT에 관심이 많고 재미있는 포스코 장차장님이 MIH 담당이셨다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;커피 타임도 자주하며 개인 일상 이야기도 나누며 15살 차이가 나지만 동네 형 같은 스타일이다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;차장님 아드님이 진짜 너무 귀엽다... 차장님 판박이.....&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;네 번째로는 '힘든 경험'이 있었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;PL은 개발자가 아니다. PL밑에 실무진은 나 혼자였고.. 선가동까지 1년 동안 혼자 모든걸 해야했다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;지표 제공처와의 줌미팅, 수집 파이프라인 구축, GPT Prompting, 현업과의 의사소통... 거진 모든걸 다 해야했다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;덕분에 짧은 기간 안에 많은 경험을 쌓고, 업무 방식을 터득했다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;힘든 경험은 평생 잊을 수 없다.. 그리고 날 힘들게 만든 norm도 잊을 수 없다 ㅋ&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스코DX 끝.&lt;/p&gt;</description>
      <category>추억, 나의 경험을 공유합니다.</category>
      <author>욘초</author>
      <guid isPermaLink="true">https://yonghyn.tistory.com/99</guid>
      <comments>https://yonghyn.tistory.com/99#entry99comment</comments>
      <pubDate>Fri, 16 Jan 2026 00:42:12 +0900</pubDate>
    </item>
    <item>
      <title>Object Detection Network [1] RCNN계열 | RCNN, SPPNet, Fast RCNN, Faster RCNN | Region Proposal with Convolution Neural Network</title>
      <link>https://yonghyn.tistory.com/98</link>
      <description>&lt;h2 id=&quot;rcnn-계열&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;RCNN 계열&lt;/h2&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;RCNN은 Region with CNN으로써, Region Proposal(영역 추정)을 기반으로한 Object Detection Network이다.&lt;br /&gt;계열을 순서대로 나열하면,&lt;br /&gt;RCNN -&amp;gt; SPPNet -&amp;gt; Fast RCNN -&amp;gt; Faster RCNN 순이다.&lt;br /&gt;이번 블로그에서는 위 네개의 RCNN들을 설명할 것이다.&lt;br /&gt;그럼 시작하자 (부릉부릉)~&lt;/p&gt;
&lt;h1 id=&quot;1-rcnn-regions-with-cnn&quot; style=&quot;color: #333e4c; text-align: start;&quot;&gt;1. RCNN (Regions with CNN)&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dh7pA/btsJQ3YCgu4/jNwwlYZc5YqjhB4jCKIbH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dh7pA/btsJQ3YCgu4/jNwwlYZc5YqjhB4jCKIbH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dh7pA/btsJQ3YCgu4/jNwwlYZc5YqjhB4jCKIbH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDh7pA%2FbtsJQ3YCgu4%2FjNwwlYZc5YqjhB4jCKIbH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;352&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;RCNN은 영역을 추정해주는 stage1과 추정한 영역으로 검출을 수행하는 stage2로 나뉘어져있다.&lt;br /&gt;stage1에서는 Region Proposal(Selective Search)를 적용해 2000개의 서로다른 region영역을 뽑아온다.&lt;br /&gt;하지만,, CNN에 input img로 활용하기 위해서는&lt;br /&gt;반드시, 이미지의 크기가 고정(227x227)되어있어야한다.&lt;br /&gt;그래서 뽑아온 region영역을 crop과 wrap을 적용해 고정크기로 바꿔준다.&lt;br /&gt;stage2에서는 받아온 2000개의 고정크기 region 영역들을 미리 훈련된 AlexNet을 통과시켜서&lt;br /&gt;1개의 input img에서 Feature Map들을 뽑아온다.&lt;br /&gt;그리고나선 Classification(분류)작업과 Regression(Bounding box)를 진행한다.&lt;br /&gt;자세히 보면 RCNN의 경우에는 Classification에서 SVM Classifier라는 새로운 알고리즘으로 적용시킨다.&lt;br /&gt;하지만 SVM을 바로 적용하면, 적중률이 떨어져서, FC Layer를 처음에 Softmax로 훈련시키고&lt;br /&gt;나온 weight(가중치)를 가지고, 그다음에는 SVM으로 진행한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AQeuf/btsJPPAxNVN/LNARPagCgv0k5N5UjpgOr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AQeuf/btsJPPAxNVN/LNARPagCgv0k5N5UjpgOr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AQeuf/btsJPPAxNVN/LNARPagCgv0k5N5UjpgOr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAQeuf%2FbtsJPPAxNVN%2FLNARPagCgv0k5N5UjpgOr0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;297&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;297&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;위 사진을 보면, region proposal로 뽑아온 2000개의 region영역들을 각각 고정된 img size(227 x 227)로 바꿔준 후,&lt;br /&gt;cnn을 들어가서 bounding box regression과 svm의 결과가 나오는것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점과 단점&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;장점 :&lt;br /&gt;동시대의 다른 알고리즘 대비 매우 높은 Detection정확도를 갖고있었다.&lt;br /&gt;Region Proposal 기반 성능을 입증했다.&lt;br /&gt;Deep Learning 기반 객체검출 성능 입증했다.&lt;br /&gt;&lt;b&gt;단점&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;:&lt;br /&gt;너무 느린 Detecion 시간, 2000개의 region 영역들을 각각 cnn을 들어가서 처리해줘야하므로 오랜 시간이 걸린다.&lt;br /&gt;그리고 너무 복잡한 아키텍처 및 학습 프로세스들이 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 id=&quot;2-sppspatial-pyramid-pooling-net--rcnn-단점을-보완&quot; style=&quot;color: #333e4c; text-align: start;&quot;&gt;2. SPP(Spatial Pyramid Pooling) Net | RCNN 단점을 보완&lt;/h1&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;SPPNet은 RCNN의 개선방안, Region Proposal된 2000개의 영역을 cnn으로 넣어선 안된다.&lt;br /&gt;SPP는 CNN상에서 Image classification에서 서로 다른 이미지 크기를 고정된 크기로 변환하는 기법이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6XxeX/btsJPTiyrMD/2JMKVEBhV9jp792VZiiBKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6XxeX/btsJPTiyrMD/2JMKVEBhV9jp792VZiiBKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6XxeX/btsJPTiyrMD/2JMKVEBhV9jp792VZiiBKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6XxeX%2FbtsJPTiyrMD%2F2JMKVEBhV9jp792VZiiBKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;446&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;446&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;RCNN을 보완하기위해서 Region Proposal로 나온 2000개의 region영역들을 CNN에 넣지않고,&lt;br /&gt;원본 img를 CNN에 넣어서 나온 Feature Map에 올려보기로 했다.&lt;br /&gt;하지만, Region영역들의 크기가 재각각이라서 해당 Feature Map들을 1D Flattened FC Input으로 고정적인&lt;br /&gt;길이의 Input Data를 만들려면 중간에 정재과정이 필요하다.&lt;br /&gt;이 정재과정을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;SPP&lt;/b&gt;가 하는 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;SPP(Spatial Pyramid Pooling)는&lt;br /&gt;Back of Visual Words(BOW)를 기반으로 나온 SPM(Spatial Pyramid Mating)에서 Max-Pooling을 적용한 것이다.&lt;br /&gt;SPM은 Feature Map에 여러 분면으로 나눈 것들에서 정보를 갖고는 방식인데.&lt;br /&gt;Max-Pooling을 적용하면, 각 분면에서 최댓값을 갖고오게된다.&lt;br /&gt;여기서 SPM 및 SPP의 최대 장점은 Input Data의 크기와는 상관없이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;나누는 분면에 따라&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;결과 크기가 달라진다는 것이다.&lt;br /&gt;즉, 기존에 영향을 받았던 서로다른 region 영역의 크기 문제에서 벗어날 수 있는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;485&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccynql/btsJPKsGNIC/Kv8WZhL81Jt3ValPTPg2I0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccynql/btsJPKsGNIC/Kv8WZhL81Jt3ValPTPg2I0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccynql/btsJPKsGNIC/Kv8WZhL81Jt3ValPTPg2I0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fccynql%2FbtsJPKsGNIC%2FKv8WZhL81Jt3ValPTPg2I0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;485&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;485&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;471&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GPpGO/btsJPOuPQXg/ieiCDTk85CsEaCjTlLQF3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GPpGO/btsJPOuPQXg/ieiCDTk85CsEaCjTlLQF3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GPpGO/btsJPOuPQXg/ieiCDTk85CsEaCjTlLQF3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGPpGO%2FbtsJPOuPQXg%2FieiCDTk85CsEaCjTlLQF3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;471&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;471&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그렇게 되면 각 분면에서 나온 최대값들을 모아서 하나의 고정된 크기의 1D FC Input Data를 만들 수 있는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;346&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nKt5U/btsJPHo98A2/KOiKFo9k64KlxAQaFdKzi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nKt5U/btsJPHo98A2/KOiKFo9k64KlxAQaFdKzi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nKt5U/btsJPHo98A2/KOiKFo9k64KlxAQaFdKzi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnKt5U%2FbtsJPHo98A2%2FKOiKFo9k64KlxAQaFdKzi1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;346&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;346&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;최종적인 SPPNet의 구조이다.&lt;br /&gt;Input Img에 대해서 이미지 자체를 CNN으로 집어 넣음과 동시에&lt;br /&gt;이미지에 대한 Region Proposal(Selective Search)를 진행한다.&lt;br /&gt;Img가 들어간 CNN에서의 Feature Map들 위에, Selective Search의 결과물로 나온 2000개의 Region들을 Mapping 시키고&lt;br /&gt;이를 SPP Layer에 넣어서 고정적인 FC Input Data로 만들어준다.&lt;br /&gt;그러면 FC Layer를 거쳐서 classification(분류)를 진행하고,&lt;br /&gt;동시에 Bounding Box Regression을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RCNN vs SPPNet&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;405&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wyeWj/btsJQgYIq9y/cEmHgVaU5LT0tOrDedYRx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wyeWj/btsJQgYIq9y/cEmHgVaU5LT0tOrDedYRx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wyeWj/btsJQgYIq9y/cEmHgVaU5LT0tOrDedYRx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwyeWj%2FbtsJQgYIq9y%2FcEmHgVaU5LT0tOrDedYRx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;405&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;405&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;SPPNet이 시간을 엄청 단축시킬 수 있음을 확인할 수 있고, 또 서로 다른 Region들에 대해 고정적인 FC Input data로 만들 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 id=&quot;3-fast-rcnn--sppnet을-보완&quot; style=&quot;color: #333e4c; text-align: start;&quot;&gt;3. Fast RCNN | SPPNet을 보완&lt;/h1&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;SPPNet에서 SPP Layer를 ROI Pooling Layer로 바꾸고,&lt;br /&gt;기존에 Classification에 있던 SVM을 Softmax로 변환하며,&lt;br /&gt;Classification과 Regression을 함께 최적화하는&lt;br /&gt;Multi-task Loss가 있는게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Fast RCNN&lt;/b&gt;이다. 그리고 End-to-End Network Learning의 시작이다.&lt;br /&gt;여기서 봐야할것은, ROI Pooling은 기존 SPP의 region영역에서 여러분면(1x1, 2x2, 4x4)으로 나누는 행위를 없애고,&lt;br /&gt;단, 하나 !&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;7 x 7로 나눈 분면을 이용한다.&lt;/b&gt;&lt;br /&gt;그리고 End-to-End는 순전파도 가능하지만, 역전파도 가능해서 결과에대한 loss를 더 확실하게 줄일 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;318&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLY94i/btsJO97HcPb/hSBfBsfCyDIj3LyPrGiuH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLY94i/btsJO97HcPb/hSBfBsfCyDIj3LyPrGiuH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLY94i/btsJO97HcPb/hSBfBsfCyDIj3LyPrGiuH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLY94i%2FbtsJO97HcPb%2FhSBfBsfCyDIj3LyPrGiuH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;318&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;318&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjQSuh/btsJQbi2TG9/RLXKM4996LdI258iTK3BW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjQSuh/btsJQbi2TG9/RLXKM4996LdI258iTK3BW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjQSuh/btsJQbi2TG9/RLXKM4996LdI258iTK3BW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjQSuh%2FbtsJQbi2TG9%2FRLXKM4996LdI258iTK3BW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;267&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Multi-task Loss&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;186&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBYo8p/btsJQF4UBvP/vQMWjj5QCRWJ5liddKTkkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBYo8p/btsJQF4UBvP/vQMWjj5QCRWJ5liddKTkkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBYo8p/btsJQF4UBvP/vQMWjj5QCRWJ5liddKTkkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBYo8p%2FbtsJQF4UBvP%2FvQMWjj5QCRWJ5liddKTkkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;186&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;186&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Fast RCNN은 SPP에서 ROI, Softmax, End2End정도만 바뀌어서 설명이 길진 않지만,&lt;br /&gt;위 세개의 바뀐 점들이 매우 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발전해도,, 남아있는 문제점&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Region Proposal에서 진행되는 Selective Search로 나온 2000개의 Region들에대한 처리가 많은 처리시간을 요구한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 id=&quot;4-faster-rcnn--rcnn계열의-최강자&quot; style=&quot;color: #333e4c; text-align: start;&quot;&gt;4. Faster RCNN | RCNN계열의 최강자&lt;/h1&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Faster RCNN = RPN(Region Proposal Network) + Fast RCNN&lt;/b&gt;&lt;br /&gt;Selective Search를 하는 Region Proposal를 Deap Learning의 Network 구조로 바꾸면,&lt;br /&gt;GPU를 사용할 수 있고, 완벽한 End-to-End를 구성할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;574&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhmwAG/btsJPDNSQ5k/4AWpibSHlZmurHDyIgMt2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhmwAG/btsJPDNSQ5k/4AWpibSHlZmurHDyIgMt2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhmwAG/btsJPDNSQ5k/4AWpibSHlZmurHDyIgMt2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhmwAG%2FbtsJPDNSQ5k%2F4AWpibSHlZmurHDyIgMt2k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;574&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;574&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Faster RCNN구조&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;325&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xcPPV/btsJQWeihRF/OdYrHiYfrTdoQ4Bp2DnJok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xcPPV/btsJQWeihRF/OdYrHiYfrTdoQ4Bp2DnJok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xcPPV/btsJQWeihRF/OdYrHiYfrTdoQ4Bp2DnJok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxcPPV%2FbtsJQWeihRF%2FOdYrHiYfrTdoQ4Bp2DnJok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;325&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;325&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;RPN도 하나의 네트워크로 안에 Classification과 Bounding Box Regression이 다 들어가있다.&lt;br /&gt;RPN에서는 대강 Object의 위치만 찾으면 되기때문에 빡세지 않고, 딥러닝 네트워크 끝에 있는 Classification과 Regression은 Object를&lt;br /&gt;확실하게 Detect해주기 위해서 열심히 훈련해야된다.&lt;br /&gt;여기서 문제점은..&lt;br /&gt;RPN의 Input Data는 Feature Map의 pixel값, Target은 Ground Truth Bouning Box이다.&lt;br /&gt;이걸 갖고 어떻게 Selective Search수준의 영역추정을 할 것인가? 이다.&lt;br /&gt;해답은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;(Reference)Anchor Box&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이다.&lt;br /&gt;Object가 있는지 없는지 후보 box로써, Anchor Box의 크기를 미리 정해놓고 Img위에 올려서 sliding window 방식으로&lt;br /&gt;이미지 전체를 천천히 훑으면서, Anchor Box안에 Object가 있는지 없는지 조사를 한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Anchor Box 구성&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZjnPL/btsJQGJk68q/ZQvSysFt8y9G5KJ6QGG7QK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZjnPL/btsJQGJk68q/ZQvSysFt8y9G5KJ6QGG7QK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZjnPL/btsJQGJk68q/ZQvSysFt8y9G5KJ6QGG7QK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZjnPL%2FbtsJQGJk68q%2FZQvSysFt8y9G5KJ6QGG7QK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;360&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Feature Map에 생기는 Anchor Point(Grid)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b04Tfk/btsJQ3qLiKy/Qvx5ithw4VM1hejizvDoQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b04Tfk/btsJQ3qLiKy/Qvx5ithw4VM1hejizvDoQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b04Tfk/btsJQ3qLiKy/Qvx5ithw4VM1hejizvDoQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb04Tfk%2FbtsJQ3qLiKy%2FQvx5ithw4VM1hejizvDoQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;454&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;454&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;원본 이미지에 생기는 Anchor Point(Grid)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;509&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xFIzp/btsJPOVU67s/ioqgMuM2j6SnkE3qJrq0KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xFIzp/btsJPOVU67s/ioqgMuM2j6SnkE3qJrq0KK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xFIzp/btsJPOVU67s/ioqgMuM2j6SnkE3qJrq0KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxFIzp%2FbtsJPOVU67s%2FioqgMuM2j6SnkE3qJrq0KK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;840&quot; height=&quot;509&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;509&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 보면, 원본 이미지(800x600)에 생기는 Anchor Point (1900개)에 총 9개의 Anchor Box가 생기니까&lt;br /&gt;1900 x 9 = 17100개의 Bounding Box가 생긴다.&lt;br /&gt;효율적인 박스 처리를 위해서&lt;br /&gt;17100개의 박스 중에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;좋은 박스&lt;/b&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;나쁜 박스&lt;/b&gt;를 걸러줘야한다.&lt;br /&gt;이 역활을 RPN (Region Proposal Network)이 수행하는 것이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RPN 구조&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cST4vz/btsJQflp8BD/GuTv7fRppxNY52CSKjPY70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cST4vz/btsJQflp8BD/GuTv7fRppxNY52CSKjPY70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cST4vz/btsJQflp8BD/GuTv7fRppxNY52CSKjPY70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcST4vz%2FbtsJQflp8BD%2FGuTv7fRppxNY52CSKjPY70%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;850&quot; height=&quot;266&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;266&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;RPN에서 입력된 Feature Map에 3x3 Convolution을 수행한다.&lt;br /&gt;그리고 1x1 Fully Convolutional Layer가 Feature Map의 크기에 상관없이&lt;br /&gt;&lt;b&gt;고정적인 FC Layer Input Data&lt;/b&gt;로 만들어준다.&lt;br /&gt;즉, 1x1FC Layer가 ROI나 SPP와 같은 역활을 하는 것이다.&lt;br /&gt;그리고 최종적으로 Classification에는 1x1conv 2x9 Output channel이 생기고&lt;br /&gt;Regression에는 1x1conv 4x9 Output channel이 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Positive Anchor Box / Negative Anchor Box&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위에서 RPN은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;좋은 박스&lt;/b&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;나쁜 박스&lt;/b&gt;를 구분한다고 했다.&lt;br /&gt;즉, Ground Truth Box와 겹치는 IOU값에 따라 Anchor Box를&lt;/p&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IOU &amp;gt;= 0.7 : Positive&lt;br /&gt;IOU Max Anchor Box : Positive&lt;br /&gt;IOUT &amp;lt; 0.3 : Negative&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;기준에 따라 Positive / Negative로 구분(labeling)한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RPN의 Classification 과 Bounding Box Regression&lt;/b&gt;&lt;br /&gt;Classification은 Anchor Box에 Positive/ Negative를 분류하는 기능을 하고,&lt;br /&gt;Regression은 Predicted box(예측 박스)와 Positive box의 차이를 줄여나가는 방향이다.&lt;br /&gt;즉, RPN은 Positive Box가 되게끔 예측해서 찾아가는 것이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 id=&quot;rpn의-loss함수&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;RPN의 Loss함수&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDVWkF/btsJQn4xEGx/2WPyxOwMpKcifUosZkbgWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDVWkF/btsJQn4xEGx/2WPyxOwMpKcifUosZkbgWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDVWkF/btsJQn4xEGx/2WPyxOwMpKcifUosZkbgWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDVWkF%2FbtsJQn4xEGx%2F2WPyxOwMpKcifUosZkbgWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;368&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;368&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 id=&quot;rpn-mini-batch&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;RPN Mini batch&lt;/h4&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Mini Batch를 정해서, 한번에 256 Anchor( 128 positive, 128 negative)씩 학습을 진행하겠다고 하자.&lt;br /&gt;Mini Batch는 학습시킬 데이터가 너무 많으면 한번에 진행하기 어려워서 여러개의 Batch들로 나눠서 진행할때 쓰이며,&lt;br /&gt;batch size가 곧, 학습시킬 데이터의 양이다.&lt;br /&gt;RPN에서 Anchor Box가 40 x 50 x 9라고하면 18000개 인데, 이른 256개씩 나눠서 순차적으로 학습하는 것이다.&lt;/p&gt;
&lt;h4 id=&quot;region-proposal-영역-filtering&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;Region Proposal 영역 Filtering&lt;/h4&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;18000개를 다 학습시킬 필요가 없다,,&lt;br /&gt;18000개 중에서 FG(four ground)만 넘겨준다.&lt;br /&gt;그리고 예측 영역 추정 박스에는 Objectness Score를 매긴다.&lt;br /&gt;Objectness Score = 예측box가 Object일 확률 (= Softmax값) x Ground Truth Bounding Box와의 IOU값&lt;br /&gt;Objectness Score가 높은 순으로 Region Proposal Box 추출을 한다.&lt;br /&gt;그러면 그 영역 안에서 이제 Object를 찾는다.&lt;/p&gt;
&lt;h4 id=&quot;faster-rcnn-training&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;Faster RCNN Training&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;371&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwww2c/btsJQVNcJLu/LaMKjJMyB9IiIDC4fIyILk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwww2c/btsJQVNcJLu/LaMKjJMyB9IiIDC4fIyILk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwww2c/btsJQVNcJLu/LaMKjJMyB9IiIDC4fIyILk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcwww2c%2FbtsJQVNcJLu%2FLaMKjJMyB9IiIDC4fIyILk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;371&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;371&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;먼저 RPN을 학습시킨다. RPN에서 Object 영역을 잘 추정할 수 있게끔, 역전파도 하면서 RPN을 최적의 상태로 만든다.&lt;br /&gt;그러고나면 Fast RCNN을 학습시킨다. Object를 잘 찾을 수 있게 학습시킨다.&lt;br /&gt;근데 여기서 문제가,,&lt;br /&gt;역전파를 하게되면, RPN에도 역전파가 들어가서 기존에 만들어놨던 최적의 RPN상태가 망가진다.&lt;br /&gt;그래서 RPN의 1x1 FC Layer(classification, regression)을 fine tuning해서 RPN에서 역전파가 수행되지않게 만든다.&lt;br /&gt;그러면 최적의 상태인 RPN은 그대로 유지되며,&lt;br /&gt;Fast RCNN의 FC Layer (공통 2개)를 fine tuning한 후,&lt;br /&gt;최종적으로 학습이 원활하게 진행되게 한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;#### Faster RCNN 최종..&lt;br /&gt;기존 RCNN계열에서 시간적인 측면과 효율적인 측면에서 모두 높은 성과를 낸 최종결과물이다.&lt;br /&gt;지금까지는 2stage detector에 대해 설명했고,&lt;br /&gt;다음 블로그로는 1stage detector이자 성능이 훨씬 더 뛰어난 애들에 대해 글을 작성하겠다.&lt;/p&gt;</description>
      <category>기술, 나의 공부를 공유합니다./[ML] Object Detection</category>
      <author>욘초</author>
      <guid isPermaLink="true">https://yonghyn.tistory.com/98</guid>
      <comments>https://yonghyn.tistory.com/98#entry98comment</comments>
      <pubDate>Sat, 28 Sep 2024 14:45:51 +0900</pubDate>
    </item>
    <item>
      <title>Object Detection Dataset [3] | Google Open Image | OPEN_IMAGE_DATASET</title>
      <link>https://yonghyn.tistory.com/97</link>
      <description>&lt;h3 id=&quot;google-open-image-dataset&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;GOOGLE OPEN IMAGE DATASET&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;YOLO와 함께 작성할 예정입니다&lt;/p&gt;</description>
      <category>기술, 나의 공부를 공유합니다./[ML] Object Detection</category>
      <author>욘초</author>
      <guid isPermaLink="true">https://yonghyn.tistory.com/97</guid>
      <comments>https://yonghyn.tistory.com/97#entry97comment</comments>
      <pubDate>Sat, 28 Sep 2024 14:45:12 +0900</pubDate>
    </item>
    <item>
      <title>Object Detection Dataset [2] | MS COCO | MS_COCO_DATASET</title>
      <link>https://yonghyn.tistory.com/96</link>
      <description>&lt;h3 id=&quot;ms-coco-dataset&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;MS COCO DATASET&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;186&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VTCWk/btsJQKydDAA/MtlkkL1vsnpcmouh3nDZrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VTCWk/btsJQKydDAA/MtlkkL1vsnpcmouh3nDZrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VTCWk/btsJQKydDAA/MtlkkL1vsnpcmouh3nDZrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVTCWk%2FbtsJQKydDAA%2FMtlkkL1vsnpcmouh3nDZrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;186&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;186&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MS COCO 데이터 세트는 PASCAL VOC 데이터세트 보다 많은&lt;br /&gt;80개의 Object Category를 갖고있으며,&lt;br /&gt;300K Img, 1.5million object를 가지고있어서,&lt;br /&gt;평균적으로 1개의 img안에 5개의 object들이 들어가있는 데이터 세트이다.&lt;br /&gt;특히, MS-COCO 2017은 Tensorflow가 나온해의 가장 많은 카테고리를 갖고있는&lt;br /&gt;데이터 세트였기 때문에,&lt;br /&gt;Tensorflow Object Detection API &amp;amp; 많은 오픈소스계열 패키지들은&lt;br /&gt;COCO Dataset으로 pretrained된 모델을 제공하고있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yYNSw/btsJQmkbLWI/lcLnHn4RAeowkTBrn8DIaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yYNSw/btsJQmkbLWI/lcLnHn4RAeowkTBrn8DIaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yYNSw/btsJQmkbLWI/lcLnHn4RAeowkTBrn8DIaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyYNSw%2FbtsJQmkbLWI%2FlcLnHn4RAeowkTBrn8DIaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;456&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;456&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;COCO 역시,&lt;br /&gt;Classification/Detection,&lt;br /&gt;Semantic &amp;amp; Instance Segmentation 을 한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;[홈페이지]&lt;br /&gt;&lt;a href=&quot;https://cocodataset.org/#home&quot;&gt;https://cocodataset.org/#home&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;coco-dataset-구성&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;COCO DATASET 구성&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rmMWk/btsJQoI6xsH/v4tMkSS6wBnKkz5gTICY5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rmMWk/btsJQoI6xsH/v4tMkSS6wBnKkz5gTICY5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rmMWk/btsJQoI6xsH/v4tMkSS6wBnKkz5gTICY5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrmMWk%2FbtsJQoI6xsH%2Fv4tMkSS6wBnKkz5gTICY5K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;309&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;309&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이와 같이 학습용, 검증용 파일에 대해서는 json파일안에 모든 정보가 함께 들어가있다.&lt;br /&gt;테스트용은 훈련시킨 모델을 테스트해보는 용도이므로 json파일에 정보가 없다.&lt;/p&gt;
&lt;h3 id=&quot;coco-dataset-사용-과정&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;COCO DATASET 사용 과정&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;필요조건 :&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #333e4c; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;COCOAPI를 다운로드 받고, pycocotools 셋업 필요&lt;/li&gt;
&lt;li&gt;cocoapi/PythonAPI로 들어간 뒤, Make install 수행&lt;/li&gt;
&lt;li&gt;site-packages에 로드 되는지 확인&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1727502273551&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pycocotools.coco import COCO
import numpy as np&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;데이터 세트 준비 :&lt;br /&gt;다운로드 위치 : objectPrj/data/coco/&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #333e4c; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;COCO 데이터 다운로드 : &lt;a href=&quot;http://cocodataset.org/#download&quot;&gt;http://cocodataset.org/#download&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2017ver. Train img file : wget &lt;a href=&quot;http://images.cocodataset.org/zips/train2017.zip&quot;&gt;http://images.cocodataset.org/zips/train2017.zip&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2017ver. Val img file : wget &lt;a href=&quot;http://images.cocodataset.org/zips/val2017.zip&quot;&gt;http://images.cocodataset.org/zips/val2017.zip&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2017ver. Train/Val annotation file : &lt;a href=&quot;http://images.cocodataset.org/annotations/annotations_trainval2017.zip&quot;&gt;http://images.cocodataset.org/annotations/annotations_trainval2017.zip&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;COCO API 활용하기 위한, annotation 파일을 로드 [code]&lt;/p&gt;
&lt;pre id=&quot;code_1727502280035&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dataDir='../../data/coco'
dataType='val2017'
annFile='{}/annotations/instances_{}.json'.format(dataDir,dataType)
coco=COCO(annFile)&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Category 정보 가져오기 [code]&lt;/p&gt;
&lt;pre id=&quot;code_1727502287818&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cats = coco.loadCats(coco.getCatIds())&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{&amp;lsquo;supercategory&amp;rsquo;: &amp;lsquo;person&amp;rsquo;, &amp;lsquo;id&amp;rsquo;: 1, &amp;lsquo;name&amp;rsquo;: &amp;lsquo;person&amp;rsquo;},&lt;br /&gt;{&amp;lsquo;supercategory&amp;rsquo;: &amp;lsquo;vehicle&amp;rsquo;, &amp;lsquo;id&amp;rsquo;: 2, &amp;lsquo;name&amp;rsquo;: &amp;lsquo;bicycle&amp;rsquo;}&amp;hellip;&lt;br /&gt;이런 형태의 카테고리 id별로 세부 정보들을 가져온다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;[추후 더 정확한 내용들을 추가할 예정입니다.]&lt;/p&gt;</description>
      <category>기술, 나의 공부를 공유합니다./[ML] Object Detection</category>
      <author>욘초</author>
      <guid isPermaLink="true">https://yonghyn.tistory.com/96</guid>
      <comments>https://yonghyn.tistory.com/96#entry96comment</comments>
      <pubDate>Sat, 28 Sep 2024 14:44:52 +0900</pubDate>
    </item>
    <item>
      <title>Object Detection Dataset [1] | PASCAL VOC 2012 | PASCAL_VOC_DATASET</title>
      <link>https://yonghyn.tistory.com/95</link>
      <description>&lt;h3 id=&quot;object-detection-dataset&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Object Detection Dataset&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;객체 검출 데이터세트는 어마무시하게 많지만, 대표적인 3가지 데이터 세트를 소개하겠습니다.&lt;br /&gt;[1] PASCAL VOC 2012 (VOC 2012) _ XML file&lt;br /&gt;[2] MS COCO _ JSON file&lt;br /&gt;[3] Google Open Image _ CSV file&lt;/p&gt;
&lt;h3 id=&quot;pascal-voc-2012-dataset&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;PASCAL VOC 2012 DATASET&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;176&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckS9J9/btsJQaRTA6M/Y9Jx5M8LcvoodbVwKyeoeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckS9J9/btsJQaRTA6M/Y9Jx5M8LcvoodbVwKyeoeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckS9J9/btsJQaRTA6M/Y9Jx5M8LcvoodbVwKyeoeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckS9J9%2FbtsJQaRTA6M%2FY9Jx5M8LcvoodbVwKyeoeK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;176&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;176&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;PASCAL VOC 2012 데이터세트는 Object Detection의 데이터세트에서 베이직으로&lt;br /&gt;여겨진다. 객체 검출을 공부했다면 기본적으로 아는 데이터 세트라고 할 수 있다.&lt;br /&gt;20개의 객체 카테고리가 존재하고,&lt;br /&gt;Classification/Detection,&lt;br /&gt;Segmentation,&lt;br /&gt;Action Classification,&lt;br /&gt;Person Layout&lt;br /&gt;의 기능을 한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Dataset은 총 5가지의 폴더를 포함하고있습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #333e4c; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Annotations : xml 파일들이 들어가있고, Image 한개당 포함하고있는 객체들의 Annotation정보를 갖고있다.&lt;/li&gt;
&lt;li&gt;ImagesET : 어떤 이미지를 train, test, trainval, val에 사용할 것인지 매핑정보를 갖고있다.&lt;/li&gt;
&lt;li&gt;JPEGImages : Detection/Segmentation에 사용될 원본 이미지로, xml과 파일명동일한 .jpg 파일들이다.&lt;/li&gt;
&lt;li&gt;SegmentationClass : Semantic Segmantation에 사용할 masking 이미지들이 있다.&lt;/li&gt;
&lt;li&gt;SegmentationObject : Instance Segmantation에 사용할 masking 이미지들이 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여기서 우리가 자주 사용할 것들은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;1. Annotations 와 3. JPEGImages&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;665&quot; data-origin-height=&quot;382&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/skgcp/btsJQ2ZHG0Z/CYKreWGpo62ThBP2Lxok60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/skgcp/btsJQ2ZHG0Z/CYKreWGpo62ThBP2Lxok60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/skgcp/btsJQ2ZHG0Z/CYKreWGpo62ThBP2Lxok60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fskgcp%2FbtsJQ2ZHG0Z%2FCYKreWGpo62ThBP2Lxok60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;665&quot; height=&quot;382&quot; data-origin-width=&quot;665&quot; data-origin-height=&quot;382&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 그림처럼 원본 이미지(JPEGImages)와 Annotations정보(Annotation)을 가지고 원본이미지에 bounding box를 시각화 시켜줘야하며, 이렇게 데이터세트를 완성시켜준다.&lt;/p&gt;
&lt;h3 id=&quot;pascal-voc-dataset-다운로드-및-정보-확인&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;PASCAL VOC DATASET 다운로드 및 정보 확인&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;데이터세트 다운로드 [shell]&lt;/p&gt;
&lt;pre id=&quot;code_1727502190824&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;!wget http://host.robots.ox.ac.uk/pascal/VOC/voc2012/VOCtrainval_11-May-2012.tar
!tar -xvf VOCtrainval_11-May-2012.tar -C ~/objectPrj/data/voc&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;objectPrj/data/voc/ 디렉터리에 폴더를 다운 받고, 압축해제까지 해준다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다운 받은 임의의 원본 이미지 확인하기 [code]&lt;/p&gt;
&lt;pre id=&quot;code_1727502197647&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import cv2
import matplotlib.pyplot as plt
%matplotlib inline

img = cv2.imread('../../data/voc/VOCdevkit/VOC2012/JPEGImages/2007_000032.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
print('img shape:', img.shape)

plt.figure(figsize=(8, 8))
plt.imshow(img_rgb)
plt.show()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nihMp/btsJPdhTCvk/Q9t5XOyelTroTqEz8QLibk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nihMp/btsJPdhTCvk/Q9t5XOyelTroTqEz8QLibk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nihMp/btsJPdhTCvk/Q9t5XOyelTroTqEz8QLibk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnihMp%2FbtsJPdhTCvk%2FQ9t5XOyelTroTqEz8QLibk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;448&quot; height=&quot;252&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공항에 비행기 2대와 정비사 2명의 모습이 보입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;해당 임의의 원본이미지에 대한 Annotation 정보 확인하기 [shell]&lt;/p&gt;
&lt;pre id=&quot;code_1727502206246&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;!cat ~/objectPrj/data/voc/VOCdevkit/VOC2012/Annotations/2007_000032.xml&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;[2007_000032.xml]&lt;/p&gt;
&lt;pre id=&quot;code_1727502215095&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;annotation&amp;gt;
	&amp;lt;folder&amp;gt;VOC2012&amp;lt;/folder&amp;gt;
	&amp;lt;filename&amp;gt;2007_000032.jpg&amp;lt;/filename&amp;gt;
	&amp;lt;source&amp;gt;
		&amp;lt;database&amp;gt;The VOC2007 Database&amp;lt;/database&amp;gt;
		&amp;lt;annotation&amp;gt;PASCAL VOC2007&amp;lt;/annotation&amp;gt;
		&amp;lt;image&amp;gt;flickr&amp;lt;/image&amp;gt;
	&amp;lt;/source&amp;gt;
	&amp;lt;size&amp;gt;
		&amp;lt;width&amp;gt;500&amp;lt;/width&amp;gt;
		&amp;lt;height&amp;gt;281&amp;lt;/height&amp;gt;
		&amp;lt;depth&amp;gt;3&amp;lt;/depth&amp;gt;
	&amp;lt;/size&amp;gt;
	&amp;lt;segmented&amp;gt;1&amp;lt;/segmented&amp;gt;
	&amp;lt;object&amp;gt;
		&amp;lt;name&amp;gt;aeroplane&amp;lt;/name&amp;gt;
		&amp;lt;pose&amp;gt;Frontal&amp;lt;/pose&amp;gt;
		&amp;lt;truncated&amp;gt;0&amp;lt;/truncated&amp;gt;
		&amp;lt;difficult&amp;gt;0&amp;lt;/difficult&amp;gt;
		&amp;lt;bndbox&amp;gt;
			&amp;lt;xmin&amp;gt;104&amp;lt;/xmin&amp;gt;
			&amp;lt;ymin&amp;gt;78&amp;lt;/ymin&amp;gt;
			&amp;lt;xmax&amp;gt;375&amp;lt;/xmax&amp;gt;
			&amp;lt;ymax&amp;gt;183&amp;lt;/ymax&amp;gt;
		&amp;lt;/bndbox&amp;gt;
	&amp;lt;/object&amp;gt;
	&amp;lt;object&amp;gt;
		&amp;lt;name&amp;gt;aeroplane&amp;lt;/name&amp;gt;
		&amp;lt;pose&amp;gt;Left&amp;lt;/pose&amp;gt;
		&amp;lt;truncated&amp;gt;0&amp;lt;/truncated&amp;gt;
		&amp;lt;difficult&amp;gt;0&amp;lt;/difficult&amp;gt;
		&amp;lt;bndbox&amp;gt;
			&amp;lt;xmin&amp;gt;133&amp;lt;/xmin&amp;gt;
			&amp;lt;ymin&amp;gt;88&amp;lt;/ymin&amp;gt;
			&amp;lt;xmax&amp;gt;197&amp;lt;/xmax&amp;gt;
			&amp;lt;ymax&amp;gt;123&amp;lt;/ymax&amp;gt;
		&amp;lt;/bndbox&amp;gt;
	&amp;lt;/object&amp;gt;
	&amp;lt;object&amp;gt;
		&amp;lt;name&amp;gt;person&amp;lt;/name&amp;gt;
		&amp;lt;pose&amp;gt;Rear&amp;lt;/pose&amp;gt;
		&amp;lt;truncated&amp;gt;0&amp;lt;/truncated&amp;gt;
		&amp;lt;difficult&amp;gt;0&amp;lt;/difficult&amp;gt;
		&amp;lt;bndbox&amp;gt;
			&amp;lt;xmin&amp;gt;195&amp;lt;/xmin&amp;gt;
			&amp;lt;ymin&amp;gt;180&amp;lt;/ymin&amp;gt;
			&amp;lt;xmax&amp;gt;213&amp;lt;/xmax&amp;gt;
			&amp;lt;ymax&amp;gt;229&amp;lt;/ymax&amp;gt;
		&amp;lt;/bndbox&amp;gt;
	&amp;lt;/object&amp;gt;
	&amp;lt;object&amp;gt;
		&amp;lt;name&amp;gt;person&amp;lt;/name&amp;gt;
		&amp;lt;pose&amp;gt;Rear&amp;lt;/pose&amp;gt;
		&amp;lt;truncated&amp;gt;0&amp;lt;/truncated&amp;gt;
		&amp;lt;difficult&amp;gt;0&amp;lt;/difficult&amp;gt;
		&amp;lt;bndbox&amp;gt;
			&amp;lt;xmin&amp;gt;26&amp;lt;/xmin&amp;gt;
			&amp;lt;ymin&amp;gt;189&amp;lt;/ymin&amp;gt;
			&amp;lt;xmax&amp;gt;44&amp;lt;/xmax&amp;gt;
			&amp;lt;ymax&amp;gt;238&amp;lt;/ymax&amp;gt;
		&amp;lt;/bndbox&amp;gt;
	&amp;lt;/object&amp;gt;
&amp;lt;/annotation&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유의 깊게 봐야할 부분은&lt;span&gt;&amp;nbsp;&lt;/span&gt;부분과&lt;span&gt;&amp;nbsp;&lt;/span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;들이다.&lt;/p&gt;
는 object 하나의 정보를 나타내는 틀이고, 그 안에 이제&lt;span&gt;&amp;nbsp;&lt;/span&gt;은 object의 이름을 나타내며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;안에는 bounding box 좌상단, 우하단 좌표 정보가 있다.&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 id=&quot;annotation-xml-파일-정보-파싱하기&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Annotation XML 파일 정보 파싱하기&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다운받은 데이터세트 코드로 불러오기 [code]&lt;/p&gt;
&lt;pre id=&quot;code_1727502222794&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import os
import random

VOC_ROOT_DIR =&quot;../../data/voc/VOCdevkit/VOC2012/&quot;
ANNO_DIR = os.path.join(VOC_ROOT_DIR, &quot;Annotations&quot;)
IMAGE_DIR = os.path.join(VOC_ROOT_DIR, &quot;JPEGImages&quot;)

xml_files = os.listdir(ANNO_DIR)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;VOC_ROOT_DIR : VOC데이터세트가 다운로드된 디렉터리&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;ANNO_DIR : 데이터세트 디렉터리 안에, Annotations 경로&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;IMAGE_DIR : 데이터세트 디렉터리 안에, JPEGImages 경로&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;xml_files : ANNO_DIR디렉터리 안에 있는 정보들을 리스트로 만든다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Annotation에서 객체 이름, 박스 위치 정보확인하기 [code]&lt;/p&gt;
&lt;pre id=&quot;code_1727502230631&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import os
import xml.etree.ElementTree as ET

xml_file = os.path.join(ANNO_DIR, '2011_006674.xml')

# XML 파일을 Parsing 하여 Element 생성
tree = ET.parse(xml_file)
root = tree.getroot()

# image 관련 정보는 root의 자식으로 존재
image_name = root.find('filename').text
full_image_name = os.path.join(IMAGE_DIR, image_name)
image_size = root.find('size')
image_width = int(image_size.find('width').text)
image_height = int(image_size.find('height').text)

# 파일내에 있는 모든 object Element를 찾음.
objects_list = []
for obj in root.findall('object'):
    # object element의 자식 element에서 bndbox를 찾음. 
    xmlbox = obj.find('bndbox')
    # bndbox element의 자식 element에서 xmin,ymin,xmax,ymax를 찾고 이의 값(text)를 추출 
    x1 = int(xmlbox.find('xmin').text)
    y1 = int(xmlbox.find('ymin').text)
    x2 = int(xmlbox.find('xmax').text)
    y2 = int(xmlbox.find('ymax').text)
    
    bndbox_pos = (x1, y1, x2, y2)
    class_name=obj.find('name').text
    object_dict={'class_name': class_name, 'bndbox_pos':bndbox_pos}
    objects_list.append(object_dict)

print('full_image_name:', full_image_name,'\n', 'image_size:', (image_width, image_height))

for object in objects_list:
    print(object)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;결과&lt;br /&gt;full_image_name: ../../data/voc/VOCdevkit/VOC2012/JPEGImages/2011_006674.jpg&lt;br /&gt;image_size: (500, 375)&lt;br /&gt;{&amp;lsquo;class_name&amp;rsquo;: &amp;lsquo;person&amp;rsquo;, &amp;lsquo;bndbox_pos&amp;rsquo;: (235, 65, 376, 221)}&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Annotation에서 Bounding box info 이용해서 원본이미지 위에 시각화 [code]&lt;/p&gt;
&lt;pre id=&quot;code_1727502238811&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import cv2
import os
import xml.etree.ElementTree as ET

xml_file = os.path.join(ANNO_DIR, '2011_006674.xml')

tree = ET.parse(xml_file)
root = tree.getroot()

image_name = root.find('filename').text
full_image_name = os.path.join(IMAGE_DIR, image_name)

img = cv2.imread(full_image_name)
# opencv의 rectangle()는 인자로 들어온 이미지 배열에 그대로 사각형을 그려주므로 별도의 이미지 배열에 그림 작업 수행. 
draw_img = img.copy()
# OpenCV는 RGB가 아니라 BGR이므로 빨간색은 (0, 0, 255)
green_color=(0, 255, 0)
red_color=(0, 0, 255)

# 파일내에 있는 모든 object Element를 찾음.
objects_list = []
for obj in root.findall('object'):
    xmlbox = obj.find('bndbox')
    
    left = int(xmlbox.find('xmin').text)
    top = int(xmlbox.find('ymin').text)
    right = int(xmlbox.find('xmax').text)
    bottom = int(xmlbox.find('ymax').text)
    
    class_name=obj.find('name').text
    
    # draw_img 배열의 좌상단 우하단 좌표에 녹색으로 box 표시 
    cv2.rectangle(draw_img, (let, topf), (right, bottom), color=green_color, thickness=1)
    # draw_img 배열의 좌상단 좌표에 빨간색으로 클래스명 표시
    cv2.putText(draw_img, class_name, (left, top - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.4, red_color, thickness=1)

img_rgb = cv2.cvtColor(draw_img, cv2.COLOR_BGR2RGB)
plt.figure(figsize=(10, 10))
plt.imshow(img_rgb)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;아래 그림 처럼, 원본 이미지위에 Annotation정보를 이용해 Bounding box를 그린다.&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;505&quot; data-origin-height=&quot;379&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MqzgS/btsJQbwC5vB/CKe6c4FxSO8J4S1y5hZId1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MqzgS/btsJQbwC5vB/CKe6c4FxSO8J4S1y5hZId1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MqzgS/btsJQbwC5vB/CKe6c4FxSO8J4S1y5hZId1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMqzgS%2FbtsJQbwC5vB%2FCKe6c4FxSO8J4S1y5hZId1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;505&quot; height=&quot;379&quot; data-origin-width=&quot;505&quot; data-origin-height=&quot;379&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;</description>
      <category>기술, 나의 공부를 공유합니다./[ML] Object Detection</category>
      <author>욘초</author>
      <guid isPermaLink="true">https://yonghyn.tistory.com/95</guid>
      <comments>https://yonghyn.tistory.com/95#entry95comment</comments>
      <pubDate>Sat, 28 Sep 2024 14:44:03 +0900</pubDate>
    </item>
    <item>
      <title>Object Detection 시작_Region Proposal, Selective Search, IOU, NMS, mAP | 객체 검출의 시작</title>
      <link>https://yonghyn.tistory.com/94</link>
      <description>&lt;h1 id=&quot;object-detection-객체-검출&quot; style=&quot;color: #333e4c; text-align: start;&quot;&gt;Object Detection 객체 검출&lt;/h1&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;영상, 이미지에서 물체(객체)를 검출 할 수 있다는 것은 어마무시한 행위이다.&lt;br /&gt;자율주행, 주민등록증 인식, 자동차 번호판 인식등등으로 수많은 행위들을 할 수 있기 때문이다.&lt;br /&gt;OpenCV(영상처리)를 하고 나서 진행하는 post이기 때문에, OpenCV를 중간중간에 사용하며&lt;br /&gt;이 파트에서 알고있어야할 중요한 라이브러리는 구글이 풀어놓은 인공지능 라이브러리 괴물, TensorFlow(텐서플로우)입니다.&lt;br /&gt;물론 PyTorch(파이토치)라는 아이도 유명합니다. 하지만 필자는 텐서플로우를 했고, 자격인증서까지 취득했으므로&lt;br /&gt;텐서플로우 코드들로 진행겠습니다.&lt;br /&gt;그럼 지금부터 객체 검출, 오브젝트 디텍션을 시작합니다.&lt;/p&gt;
&lt;h2 id=&quot;classification--localization--detection--segmentation&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Classification / Localization / Detection / Segmentation&lt;/h2&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Classification[분류] : 이미지상에서 객체가 무엇인지 판별합니다.&lt;br /&gt;Localization[발견] : 이미지상에서 객체 하나를 bounding box로 지정하여 찾습니다.&lt;br /&gt;Detection[발견] : 이미지상에서 여러개의 객체를 bounding box로 지정하여 찾습니다.&lt;br /&gt;Segmentation[분할] : 이미지상에서 여러개의 객체를 pixel단위로 라벨링해서 그룹화시켜서 물체 모양대로 검출한다.&lt;br /&gt;디텍션보다 발전한 형태이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;255&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eBhp5P/btsJPGql5kH/cWXKAmLJZSPSaOXSLu1HSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eBhp5P/btsJPGql5kH/cWXKAmLJZSPSaOXSLu1HSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eBhp5P/btsJPGql5kH/cWXKAmLJZSPSaOXSLu1HSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeBhp5P%2FbtsJPGql5kH%2FcWXKAmLJZSPSaOXSLu1HSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;255&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;255&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&quot;object-detection-history&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Object Detection History&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EGNjC/btsJQJ0m6Vu/OjBENA0D2Fl0yJb07qU4j0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EGNjC/btsJQJ0m6Vu/OjBENA0D2Fl0yJb07qU4j0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EGNjC/btsJQJ0m6Vu/OjBENA0D2Fl0yJb07qU4j0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEGNjC%2FbtsJQJ0m6Vu%2FOjBENA0D2Fl0yJb07qU4j0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;242&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Alex Net을 기점으로 객체 검출에 Deap Learning을 기초로한 method들이 나왔다.&lt;br /&gt;(two-stage, rcnn계열)RCNN -&amp;gt; SPPNet -&amp;gt; Fast RCNN -&amp;gt; Faster RCNN 순으로 발전했으며,&lt;br /&gt;two-stage는 첫번째 층에서 영역을 추천해주고 두번째 층에서 분류과 bounding box처리를 진행한다.&lt;br /&gt;(one-stage)YOLO , SSD, Retina-Net 이 있다.&lt;br /&gt;one-stage는 영역 추정(Region Proposald)와 분류(Classification)과 Bounding Box를 함께 처리한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;현재 YOLO 알고리즘이 Real-Time에서 성능이 좋아 자주 쓰이며,&lt;br /&gt;Real-Time에 한계는 있으나 성능이 가장 좋은 모델은 Retina-Net이다.&lt;/p&gt;
&lt;h2 id=&quot;object-detection-구성-요소&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Object Detection 구성 요소&lt;/h2&gt;
&lt;h3 id=&quot;1-영역-추정--region-proposal-selective-search&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;1. 영역 추정 , Region-Proposal (Selective Search)&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;초기 객체 검출에서 자주 쓰인 방식은 sliding window 방식이다.&lt;br /&gt;특정 사이즈의 커널을 이미지상에서 천천히 움직여 해당 커널안의 픽셀들의 정보를 갖고 처리한다.&lt;br /&gt;슬라이딩 윈도우는 추후, Convolution 컨벌루션 연산을 하기위해 쓰이며&lt;br /&gt;우리가 알아야할 간단한 슬라이딩 윈도우의 정보는 kernel(=window)와 anchor point(중심점) 정도가 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;256&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPO5CE/btsJPBW1jOy/mzUFuANAFMIzxENLgCLlGK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPO5CE/btsJPBW1jOy/mzUFuANAFMIzxENLgCLlGK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPO5CE/btsJPBW1jOy/mzUFuANAFMIzxENLgCLlGK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bPO5CE/btsJPBW1jOy/mzUFuANAFMIzxENLgCLlGK/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;256&quot; height=&quot;377&quot; data-origin-width=&quot;256&quot; data-origin-height=&quot;377&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;방향성은 다르지만 슬라이딩 윈도우보다 개선된 객체를 찾는 방법,&lt;br /&gt;영역 추정 Resion Proposal 으로 Selective Search가 등장한다.&lt;br /&gt;&lt;b&gt;Selective Search&lt;/b&gt;는 빠른 검출(Detection)과 높은 재현율(Recall) 예측 성공을 한다.&lt;br /&gt;즉, 객체가 있을만한 영역을 잘 찍어준다.&lt;br /&gt;특징으론, 이미지내의 모든 객체의 크기를 고려하며 색상.재질.크기.무늬 등 다양한 조건을 고려해준다.&lt;br /&gt;이미지에서 위 조건들로 유사한 영역끼리 그룹화시켜준다.&lt;br /&gt;그리고 빠른 속도를 자랑한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;276&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dAnSFj/btsJRd7VQbm/e7S5iSEbaYSc6yyG6KiXw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dAnSFj/btsJRd7VQbm/e7S5iSEbaYSc6yyG6KiXw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dAnSFj/btsJRd7VQbm/e7S5iSEbaYSc6yyG6KiXw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdAnSFj%2FbtsJRd7VQbm%2Fe7S5iSEbaYSc6yyG6KiXw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;276&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;276&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;순서 :&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #333e4c; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;개별 segment된 모든 부분들을 모두 bounding box처리를 해서 region proposal리스트에 추가한다.&lt;/li&gt;
&lt;li&gt;개별 segment된 부분들을 가지고 컬러, 무늬, 크기, 형태에 따라 유사도가 비슷한 것들끼리 그룹화한다.&lt;/li&gt;
&lt;li&gt;위 1, 2번작업들을 반복 수행한다.&lt;/li&gt;
&lt;li&gt;그러다 보면 최종적으로 이미지내에서 객체를 탐지하는 bounding box들이 남는다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 id=&quot;2-detection-을-위한-deap-learning-network-구성&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;2. Detection 을 위한 Deap Learning Network 구성&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;396&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zMf4H/btsJRboLUrd/NsfZ57F8cu19KSm2tlpXh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zMf4H/btsJRboLUrd/NsfZ57F8cu19KSm2tlpXh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zMf4H/btsJRboLUrd/NsfZ57F8cu19KSm2tlpXh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzMf4H%2FbtsJRboLUrd%2FNsfZ57F8cu19KSm2tlpXh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;660&quot; height=&quot;396&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;396&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;back-end로써 뒤에서 더 정확히 다루겠지만, 이부분에서는 Feature Extraction (특징 추출), Network Prediction(네트웍 예측) 등이 이뤄진다.&lt;br /&gt;앞서 설명한 object detection의 history에 등장했던 모델들이 이부분에서 쓰이며,&lt;br /&gt;대표적으로 RCNN계열, SSD, Retina-NET이 있고, YOLO도 사용하지만 앞 모델들과는 독자적인 길을 걷고있는 아이이다.&lt;br /&gt;YOLO를 주의깊게 봐야한다. (언제 어마무시하게 성장할지 모르는 아이다. )&lt;br /&gt;back-bone으로는 Resnet을 범용으로 사용하며, Tensorflow API를 사용할떈 Inception/ Mobile Net을 쓴다.&lt;/p&gt;
&lt;h3 id=&quot;3-detection에서-사용하는-평가-지표&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3. Detection에서 사용하는 평가 지표&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;IOU, NMS, mAP가 존재한다.&lt;/p&gt;
&lt;h4 id=&quot;3-1-iou-interest-over-unit&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;3-1 IOU (Interest Over Unit)&lt;/h4&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;IOU는 모델이 예측한 결과가 실제값과 얼마나 유사한지 확인해보는 표이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;173&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AYJkH/btsJQlr5LCz/KDuqXXlTxs5neIBuInxGn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AYJkH/btsJQlr5LCz/KDuqXXlTxs5neIBuInxGn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AYJkH/btsJQlr5LCz/KDuqXXlTxs5neIBuInxGn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAYJkH%2FbtsJQlr5LCz%2FKDuqXXlTxs5neIBuInxGn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;173&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;173&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dXR67P/btsJQxTo2e3/knP5iFMiE9U5Zw0CnrpTh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dXR67P/btsJQxTo2e3/knP5iFMiE9U5Zw0CnrpTh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dXR67P/btsJQxTo2e3/knP5iFMiE9U5Zw0CnrpTh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdXR67P%2FbtsJQxTo2e3%2FknP5iFMiE9U5Zw0CnrpTh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;263&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;정확히는 실제 객체의 bounding box와 예측한 bounding box를 가지고 교집합 영역을 합집합 영역으로 나눈 결과값이다.&lt;br /&gt;1에 가까울수록 예측한 bounding box가 실제 객체의 bounding box와 차이가 없다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;IOU 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727502153650&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import numpy as np

def compute_iou(prec_box, answ_box):
    x1 = np.maximum(prec_box[0], asnw_box[0])
    y1 = np.minimum(prec_box[1], answ_box[1])
    x2 = np.minimum(prec_box[2], answ_box[2])
    y2 = np.maximum(prec_box[3], answ_box[3])

    intersection = np.maximum(x2 - x1, 0) * np.maximum(y2 - y1, 0)

    prec_box_area = (prec_box[2] - prec_box[0]) * (prec_box[3] - prec_box[1])
    answ_box_area = (answ_box[2] - answ_box[0]) * (answ_box[3] - answ_box[1])

    union  = prec_box_area + answ_box_area - intersection

    iou = intersection / union

    return (iou)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;prec_box : 예측한 bounding box, 박스 좌측 상단 좌표(prec_box[0], prec_box[1]), 박스 우측 하단 좌표(prec_box[2], prec_box[3])&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;answ_box : 실제 bounding box&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;intersection : 예측한 박스와 실제 박스의 교집합 영역&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;union : 예측한 박스와 실제 박스의 합집합 영역&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 id=&quot;3-2-nms-non-max-supression&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;3-2 NMS (Non-Max Supression)&lt;/h4&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;NMS는 Detect된 bounding box중에서 가장 적합한 box만 남기고 모두 제거하는 필터역할을 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1117&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dW43Sw/btsJPKzmYwg/rkYDUyTlDSuu4SYKIiyvj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dW43Sw/btsJPKzmYwg/rkYDUyTlDSuu4SYKIiyvj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dW43Sw/btsJPKzmYwg/rkYDUyTlDSuu4SYKIiyvj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdW43Sw%2FbtsJPKzmYwg%2FrkYDUyTlDSuu4SYKIiyvj0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;500&quot; data-origin-width=&quot;1117&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;NMS를 적용하기 전 이미지를 보면,&lt;br /&gt;Object Detection알고리즘은 object가 있을만한 위치에&lt;br /&gt;많은 Detection(즉, bounding box 처리)를 하는 경향이 있다. 그래서 우리는 불필요한 box들을 제거해줄 필요가 있다.&lt;br /&gt;NMS를 적용해 우측 이미지를 보면, bounding box가 하나만 남아있는 걸 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bETkJz/btsJQUneQEC/AaHBLKA0UJM0t3pC6uuzV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bETkJz/btsJQUneQEC/AaHBLKA0UJM0t3pC6uuzV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bETkJz/btsJQUneQEC/AaHBLKA0UJM0t3pC6uuzV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbETkJz%2FbtsJQUneQEC%2FAaHBLKA0UJM0t3pC6uuzV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;508&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;NMS는 confidence threshold(예측 임계값), iou threshold(iou 임계값)을 받아온다.&lt;br /&gt;수행 로직은 다음과 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #333e4c; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Detected된 bounding box별로 특정 confidence threshold 이하의 값을 갖는 bounding box는 모두 제거한다.&lt;/li&gt;
&lt;li&gt;가장 높은 confidence score를 가진 box순으로 내림차순 정렬을 한다.&lt;/li&gt;
&lt;li&gt;높은 confidence score를 가진 box와 겹치는 또 다른 box를 정렬 순서대로 조사하여 iou가 특정 threshold(임계값)보다 큰 box들은 모두 제거한다.&lt;/li&gt;
&lt;li&gt;2, 3번 과정을 정렬순서대로 진행한다.&lt;/li&gt;
&lt;li&gt;남아있는 객체 bounding box를 선택한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 id=&quot;3-3-map-mean-average-precision&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;3-3 mAP (mean Average Precision)&lt;/h4&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;실제 object가 detect된 재현율(Recall)의 변화에 따른 정밀도(Precision)의 값을 평균한 성능 수치이다.&lt;br /&gt;mAP를 하기위해선&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;정밀도&lt;/b&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;재현율&lt;/b&gt;을 잘 알고있어야한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o96Nb/btsJQBuLEKd/ORq2B8Lg1UfvQUi67pJQDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o96Nb/btsJQBuLEKd/ORq2B8Lg1UfvQUi67pJQDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o96Nb/btsJQBuLEKd/ORq2B8Lg1UfvQUi67pJQDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo96Nb%2FbtsJQBuLEKd%2FORq2B8Lg1UfvQUi67pJQDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;278&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;TN : 틀린 값) 실제값과 동일하게 예측한 것이다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;FP : 실제값과 다르게 예측한 것이다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;FN : 실제값을 예측하지 못 한것이다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;TP : 맞는 값) 실제값을 예측 성공한 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정밀도 (= TP / (FP + TP))&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예측을 positive로한 대상중에서 예측과 실제값이 positive로 일치한 데이터의 비율이다.&lt;br /&gt;즉, 예측한 것중에 실제값과 일치한 데이터의 비율을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재현율 (= TP / (FN + TP))&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;실제값이 positive한 대상중에서 예측과 실제값이 positive로 일치한 데이터의 비율이다.&lt;br /&gt;즉, 실제값 중에서 예측에 성공한 실제 데이터의 비율을 의미한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;confidence threshold(임계값)에 따른 재현율과 정밀도의 변화이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHvisU/btsJPOn5Pfq/6kCtTAiazZn9YI6BNHDPhK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHvisU/btsJPOn5Pfq/6kCtTAiazZn9YI6BNHDPhK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHvisU/btsJPOn5Pfq/6kCtTAiazZn9YI6BNHDPhK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHvisU%2FbtsJPOn5Pfq%2F6kCtTAiazZn9YI6BNHDPhK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;282&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;282&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;임계값이 높으면, bounding box를 만들 확률이 낮아지고, 정밀도는 상승하며, 재현율은 하락한다.&lt;br /&gt;임계값이 낮으면, bounding box를 만들 확률이 높아지고, 정밀도는 하락하며, 재현율은 상승한다.&lt;br /&gt;임계값과 정밀도는 비례하며, 재현율과는 반비례한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kz8P6/btsJP78LpVs/IGcDVtA1KCQ5Tuw4IfqJF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kz8P6/btsJP78LpVs/IGcDVtA1KCQ5Tuw4IfqJF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kz8P6/btsJP78LpVs/IGcDVtA1KCQ5Tuw4IfqJF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fkz8P6%2FbtsJP78LpVs%2FIGcDVtA1KCQ5Tuw4IfqJF0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;426&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;426&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;재현율과 정밀도 그래프를 보면&lt;br /&gt;빨간색 공간 영역이 AP(평균 예측율)이다.&lt;br /&gt;객체 하나에 대한 AP가 이렇게 구해진다.&lt;br /&gt;&lt;b&gt;우리가 구하는 이미지에서의 mAP는 이미지 상의 모든 객체 AP에 대한 평균이다.&lt;/b&gt;&lt;/p&gt;</description>
      <category>기술, 나의 공부를 공유합니다./[ML] Object Detection</category>
      <author>욘초</author>
      <guid isPermaLink="true">https://yonghyn.tistory.com/94</guid>
      <comments>https://yonghyn.tistory.com/94#entry94comment</comments>
      <pubDate>Sat, 28 Sep 2024 14:42:40 +0900</pubDate>
    </item>
    <item>
      <title>OpenCV 이미지 검출[3]_직선 검출, 원 검출 | 주요 특징점 검출, 이미지내의 객체를 검출한다</title>
      <link>https://yonghyn.tistory.com/93</link>
      <description>&lt;h2 id=&quot;5-직선-검출&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;5. 직선 검출&lt;/h2&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;직선 검출은 이미지내에서 선형적인 부분들을 검출한다.&lt;br /&gt;직선 도로에서 도로의 차선이라든지, 건물의 외형들을 검출할 수 있다.&lt;br /&gt;직선 검출 알고리즘은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;허프 변환 (Hough Transform)&lt;/b&gt;을 활용해 직선을 검출한다.&lt;br /&gt;허프변환은 이미지 내의 어떤 점이라도 선의 일부일 수 있다는 가정하에 직선의 방정식을 이용해 직선을 검출한다.&lt;br /&gt;OpenCV에서 특히, 이분야에서는 삼각함수를 이용한 직선의 방정식을 구한다.&lt;br /&gt;(이유는 그냥 직선의 방정식에는 한계들이 존재하기 때문이다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4TnRM/btsJPP1zmFC/AaDO8t19LGQDNJ9iJzQmzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4TnRM/btsJPP1zmFC/AaDO8t19LGQDNJ9iJzQmzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4TnRM/btsJPP1zmFC/AaDO8t19LGQDNJ9iJzQmzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4TnRM%2FbtsJPP1zmFC%2FAaDO8t19LGQDNJ9iJzQmzK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;392&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;392&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위와 같은 원점으로부터 각도와 거리로 직선의 방정식을 표현할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;298&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQWTcL/btsJPPHk1A3/D9EQFZFEZNttObMW9OFD10/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQWTcL/btsJPPHk1A3/D9EQFZFEZNttObMW9OFD10/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQWTcL/btsJPPHk1A3/D9EQFZFEZNttObMW9OFD10/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQWTcL%2FbtsJPPHk1A3%2FD9EQFZFEZNttObMW9OFD10%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;298&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;298&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 그림을 설명하겠습니다.&lt;br /&gt;각도 (0&amp;rsquo; ~ 180&amp;rsquo;)별로 원점에서 거리와 각도가 동일한 직선을 찾는 것이다.&lt;br /&gt;p1점을 기준으로 a각도에서 b만큼의 직선까지의 거리가 나온 직선 A1을 기준으로하자,&lt;br /&gt;그러면 P2점을 기준으로 각도를 0 부터 180 도까지 천천히 올려가면서 a각도일때 p2를 지나는 직선, B1을 찾으면 해당 직선으로부터 원점까지의 거리가 b인경우,&lt;br /&gt;우린 A1직선과 B1직선을 누적 시켜서 이게 이미지내에서 직선일 경우라고 생각하는 것이다.&lt;/p&gt;
&lt;h3 id=&quot;3개의-허프-변환&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3개의 허프 변환&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;OpenCV에서는 세 종류의 변환을 지원한다.&lt;br /&gt;&lt;b&gt;표준 허프 변환&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;멀티 스케일링 허프 변화&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;점진성 확률적 허프 변환&lt;/b&gt;&lt;/p&gt;
&lt;h4 id=&quot;표준-허프-변환--멀티-스케일링-허프-변환&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;표준 허프 변환 &amp;amp; 멀티 스케일링 허프 변환&lt;/h4&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;허프 변환 함수는 표준 허프 변환과 멀티 스케일링 허프 변환을 동시에 지원한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;허프 변환 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727502012127&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;lines = cv2.HoughLines(
	image,
	rho,
	theta,
	threshold,
	srn = None,
	stn = None,
	min_theta = None,
	max_theta = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;image : 입력이미지, 8bit 단일 채널 이미지를 사용하며 일반적으로 이진화 함수나 캐니 엣지 함수의 결과를 인수로 활용한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;rho : 거리, 단위는 0.0 ~ 1.0을 사용한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;theta : 각도, 라디안을 사용하며 0 ~ 180의 범위에서 사용한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;threshold : 임계값, 직선을 결정하기 위해 만족해야되는 누산 평면의 값 즉, 몇개 이상의 동일한 직선이 존재해야 해당 직선을 이미지에서 중요한 직선으로 인식할 것인지 결정한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;srn : 거리에 대한 약수, (여기서 부터 멀티 스케일링 허프 변환 변수)&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;stn : 각도에 대한 약수, 거리와 각도는 정규화된 값이 아니므로 멀리 스케일링은 거리와 각도의 값을 조정하기 위해 srn과 stn을 사용한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;min_theta : 최소 각도,&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;max_theta : 최대 각도, OpenCV에서는 최소, 최대 각도를 이용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;점진성-확률적-허프-변환&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;점진성 확률적 허프 변환&lt;/h4&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;앞에 설명한 변환들은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;모든 점&lt;/b&gt;에서 직선을 찾는다.&lt;br /&gt;이렇게 할 경우 비교적 많은 시간이 들지만,&lt;br /&gt;점진성 확률적 허프 변환은 이미지 픽셀중 몇개만 (확률적)&lt;br /&gt;즉 임의의 점 몇개만 누적해서 계산한다.&lt;br /&gt;이 알고리즘은 시작점과 끝점을 반환한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;확률 허프 변환 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727502019305&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;lines = cv2.HoughLinesP(
	image,
	rho,
	theta,
	threshold,
	minLineLength = None,
	maxLineGap = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;image : 입력 이미지&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;rho : 거리&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;theta : 각도&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;threshold : 임계값, 모두 허프 변환과 동일한 의미&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;minLineLength : 최소 선 길이, 검출된 직선이 가져야할 최소한의 선 길이, 이 값도 짧은 직선은 취급 안한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;maxLineGap : 최대 선 간격, 검출된 선 사이의 최대 허용 간격, 이 값보다 간격이 좁은 경우 직선으로 취급 안한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 id=&quot;실습-코드&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;실습 코드&lt;/h4&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;허프 변환 예제&lt;/p&gt;
&lt;pre id=&quot;code_1727502026313&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import cv2
import numpy as np

src = cv2.imread(&quot;trump_card_1.jpg&quot;)
dst = src.copy()

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3), (-1, -1))

gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
morp = cv2.dilate(binary, kernel)
morp = cv2.erode(morp, kernel, iterations=3)
morp = cv2.dilate(morp, kernel, iterations=2)
canny = cv2.Canny(morp, 0, 0, apertureSize=3, L2gradient=True)

lines = cv2.HoughLines(canny, 1, np.pi/180, 100, srn= 50, stn=10, min_theta=0, max_theta=np.pi/2)

for i in lines:
	rho, theta = i[0][0], i[0][1]
	a, b = np.cos(theta), np.sin(theta)
	x0, y0 = a*rho, b*rho
	
	scale = src.shape[0] + src.shape[1]

	x1 = int(x0 + scale * -b)
	y1 = int(y0 + scale * a)
	x2 = int(x0 - scale * -b)
	y2 = int(y0 - scale * a)

	cv2.line(dst, (x1, y1), (x2, y2), (0, 255, 255), 2)
	cv2.circle(dst, (x0, y0), 3, (255, 0, 0), 5, cv2.FILLED)

cv2.imshow(&quot;dst&quot;, dst)
cv2.waitKey(0)
cv2.destroyAllWindows()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;505&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eJEl3Y/btsJPMKyn2D/kRAqh19ORA5kmSaOX9U0y1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eJEl3Y/btsJPMKyn2D/kRAqh19ORA5kmSaOX9U0y1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eJEl3Y/btsJPMKyn2D/kRAqh19ORA5kmSaOX9U0y1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeJEl3Y%2FbtsJPMKyn2D%2FkRAqh19ORA5kmSaOX9U0y1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;505&quot; height=&quot;534&quot; data-origin-width=&quot;505&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;전처리가 진행된 이미지에 멀티 스케일 허프 변환을 적용한 코드이다.&lt;br /&gt;허프 변환은 모든 점에 대해 직선의 방정식을 구하기 때문에&lt;br /&gt;최대한 점의 성분을 제거한다.&lt;br /&gt;그래서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;그레이스케일&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이진화&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;모폴로지 연산&lt;/b&gt;을 차례대로 적용했으며&lt;br /&gt;모폴로지 연산을 통해 노이즈를 최대한 제거했다.&lt;br /&gt;그런 다음, 캐니 엣지를 적용해 가장자리 선분만 남긴다.&lt;br /&gt;그러면 허프 변환 함수는 가장자리 선분들만 이용해서 직선을 찾는 것이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;6-원-검출&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;6. 원 검출&lt;/h2&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;원 검출은 허프 변환 알고리즘 중 하나인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;허프 원 변환&lt;/b&gt;알고리즘을 활용해 원을 검출한다.&lt;br /&gt;허프 원 변환 알고리즘은 2차원 평면이 아닌, 3차원 누산 평면을 검출한다.&lt;br /&gt;2차원 공간 (x, y)에서 3차원 공간 (x, y, z)로 변한 것이다.&lt;br /&gt;하지만 이러면 N^3 (n은 차원)바이트 메모리를 필요로 하기 때문에,, 우린 3차원을 2차원으로 나눠서 계산 한다.&lt;br /&gt;(추후 설명은 넘어가겠다. 원 검출은 많이 사용하지 않는다..!?)&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;허프 원 변환 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727502034486&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;circles = cv2.HoughCircles(
	image,
	method,
	dp,
	minDist,
	param1 = None,
	param2 = None,
	minRadius = None,
	maxRadius = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;image : 입력 이미지, 8bit 단일 채널 그레이 스케일 형태 이미지 사용 (이진화 x)&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;method : 검출 방법, 항상 2단계 허프 변환&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;21HT&lt;/b&gt;를 사용한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;dp : 해상도 비율, 원의 중심을 검출하는데 사용하는 누산 평면 해상도, 인수를 1로 지정할 경우 입력이미지와 동일한 해상도를 갖는다. 인수를 2로 지정할 경우 입력 이미지의 1/2 크기로 줄어든다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;minDist : 최소 거리, 검출된 원과 원 사이의 최소 거리&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;param1 : 캐니 엣지 임계값, 허프 변환에서 자체적으로 캐니 엣지를 수행하는데, 이때 사용되는 상위 임계값이다. (하위 임계값은 자동으로 상위임계값의 1/2 값을 갖는다.)&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;param2 : 중간 임계값, 누산 평면에 대한 임계값으로 값이 낮을 수록 많은 원들이 검출된다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;minRadius : 최소 반지름&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;maxRadius : 최대 반지름, 원의 반지름 범위&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;허프 원 변환 예제&lt;/p&gt;
&lt;pre id=&quot;code_1727502042057&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import cv2

src = cv2.imread(&quot;golf_ball.png&quot;)
dst = src.copy()

image = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)

circles = cv2.HoughCircles(image, cv2.HOUGH_GRADIENT, 1, 100, param1= 100, param2=35, minRadius=80, maxRadius=120)

for i in circles[0]:
	cv2.circle(dst, (i[0], i[1]), i[2], (255,255,255), 5)


cv2.imshow(&quot;dst&quot;, dst)
cv2.waitKey(0)
cv2.destroyAllWindows()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMAqxm/btsJQhDgJBn/UXZKGfAyFt3JAOiNn5l2Y0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMAqxm/btsJQhDgJBn/UXZKGfAyFt3JAOiNn5l2Y0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMAqxm/btsJQhDgJBn/UXZKGfAyFt3JAOiNn5l2Y0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMAqxm%2FbtsJQhDgJBn%2FUXZKGfAyFt3JAOiNn5l2Y0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;292&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>기술, 나의 공부를 공유합니다./[ML] Object Detection</category>
      <author>욘초</author>
      <guid isPermaLink="true">https://yonghyn.tistory.com/93</guid>
      <comments>https://yonghyn.tistory.com/93#entry93comment</comments>
      <pubDate>Sat, 28 Sep 2024 14:40:55 +0900</pubDate>
    </item>
    <item>
      <title>OpenCV 이미지 검출[2]_다각형 근사, 코너 검출 | 주요 특징점 검출, 이미지내의 객체를 검출한다</title>
      <link>https://yonghyn.tistory.com/92</link>
      <description>&lt;h2 id=&quot;3-다각형-근사&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;3. 다각형 근사&lt;/h2&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다각형 근사는 검출된 윤곽선의 형상을 분석할 시 정점의 수가 적은 다각형으로 표현하도록 하는 근사방법이다.&lt;br /&gt;즉, 이미지에서 검출된 그룹화된 윤곽선 정보를 갖고 최대한 적은 정점을 갖는 다각형으로 표현하는 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다각형 근사는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;더글라스-패커(Douglas-peucker)알고리즘&lt;/b&gt;을 사용한다.&lt;br /&gt;위 알고리즘은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;근사치 정확도 (Epsilon)&lt;/b&gt;의 값으로 기존의 다각형과 윤곽점이 압축된 다각형의 최대편차를 고려해 최종 다각형을 근사하게된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;472&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b44IXV/btsJO3sXtqD/NLuXql5bQus0Oe0ZRgxOl0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b44IXV/btsJO3sXtqD/NLuXql5bQus0Oe0ZRgxOl0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b44IXV/btsJO3sXtqD/NLuXql5bQus0Oe0ZRgxOl0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/b44IXV/btsJO3sXtqD/NLuXql5bQus0Oe0ZRgxOl0/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;472&quot; height=&quot;150&quot; data-origin-width=&quot;472&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;더글라스-패커 알고리즘은 위와같이 적용된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;695&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnokQ2/btsJQUOhYZ4/AMkLnNCLQYWXjkZLfWzKe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnokQ2/btsJQUOhYZ4/AMkLnNCLQYWXjkZLfWzKe0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnokQ2/btsJQUOhYZ4/AMkLnNCLQYWXjkZLfWzKe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnokQ2%2FbtsJQUOhYZ4%2FAMkLnNCLQYWXjkZLfWzKe0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;695&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;695&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 짧은 영상을 순서대로 정리해놓은 그림이다.&lt;br /&gt;굵은 점들이 윤곽점, 검은색 실선이 윤곽선들이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #333e4c; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;두 극점을 선택한 후 선으로 연결한다. =&amp;gt; (a)라는 선&lt;/li&gt;
&lt;li&gt;그리고 해당 선에 근사치 정확도, 즉 epsilon을 적용한다.&lt;/li&gt;
&lt;li&gt;근사치 정확도에 포함되지 않는 점들 중, 선분에서 가장 멀리있는 점을 선택하고 연결한다. =&amp;gt; (c)라는 윤곽점을 선택 후 연결&lt;/li&gt;
&lt;li&gt;이젠 그럼 (c)를 기준으로 오른쪽 방향으로 제일 거리가 먼 점을 선택후 연결, 위 1, 2번 작업을 반복한다.&lt;/li&gt;
&lt;li&gt;정점이 적은 다각형을 근사한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다각형 근사 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501896326&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;approxCurve = cv2.approxPolyDP(
	curve,
	epsilon,
	closed
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;curve : 윤곽선, 윤곽선 검출 함수에서 검출된 윤곽선, 배열구성 윤곽점을 활용한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;epsilon : 근사치 정확도, 입력된 다각형과 반환될 근사 다각형 사이의 최대 편차 간격을 의미한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;closed : 폐곡선, 시작점과 끝점의 연결 여부, True = 마지막점과 첫번째 점을 연결한다.&lt;br /&gt;True로 해야 완벽한 다각형이 완성된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다각형 근사 예제&lt;/p&gt;
&lt;pre id=&quot;code_1727501903963&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import cv2

src = cv2.imread(&quot;gomtange.jpg&quot;)
dst = src.copy()

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))

gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 230, 255, cv2.THRESH_BINARY)
morp = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel, iterations=2)
image = cv2.bitwise_not(morp)

contours, hierarchy = cv2.findContours(image, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

for i in contours:
	perimeter = cv2.arcLength(i, True)
	epsilon = perimeter * 0.05
	approx = cv2.approxPolyDP(i, epsilon, True)
	cv2.drawContours(dst, [approx], 0, (0,0,255), 3)
	for j in approx:
		cv2.circle(dst, tuple(j[0]), 3, (255,0,0), -1)

cv2.imshow(&quot;dst&quot;, dst)
cv2.waitKey(0)
cv2.destroyAllWindows()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZwfcz/btsJQzp9ksz/rVK7oY4hA7WhS5H3qz9Rx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZwfcz/btsJQzp9ksz/rVK7oY4hA7WhS5H3qz9Rx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZwfcz/btsJQzp9ksz/rVK7oY4hA7WhS5H3qz9Rx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZwfcz%2FbtsJQzp9ksz%2FrVK7oY4hA7WhS5H3qz9Rx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;573&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 id=&quot;1-윤곽선-길이-계산&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;(1) 윤곽선 길이 계산&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선의 길이를 계산한다.&lt;br /&gt;윤곽선 길이 계산 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501912312&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;length = cv2.arcLength(
	curve,
	closed
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;curve : 윤곽선&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;closed : 폐곡선, 윤곽선의 닫힘 여부 (True or False)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;2-윤곽선-면적-계산&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;(2) 윤곽선 면적 계산&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선 내부의 면적을 계산한다.&lt;br /&gt;윤곽선 면적 계산 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501918548&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;area = cv2.contourArea(
	contour,
	oriented
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;contour : 윤곽선&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;oriented : 방향성, 계산된 윤곽선 면적의 부호를 의미한다. 방향성이 참 일 경우, 윤곽선의 방향에 따라 부호가있는 면적 값을 반환하고. 거짓 일 경우, 절댓값으로 계산된 값으로 반환된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;3-윤곽선-경계-사각형-매우-중요&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;(3) 윤곽선 경계 사각형 (매우 중요)&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선의 경계면을 둘러싸는 사각형을 구한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선 경계 사각형 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501925415&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;boundrect = cv2.boundingRect(
	curve
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;curve : 윤곽선&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;4-윤곽선-최소-면적-사각형-중요&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;(4) 윤곽선 최소 면적 사각형 (중요)&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선의 경계면을 둘러싸는 최소 크기의 사각형을 계산한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선 최소 면적 사각형 계산 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501933895&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rect = cv2.minAreaRect(
	points
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;points : 윤곽선&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;5-윤곽선-최소-면적-원&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;(5) 윤곽선 최소 면적 원&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선의 경계면을 둘러싸는 최소 크기의 원을 계산한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선 최소 면적 원 계산 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501940550&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;center, radius = cv2.minEnclosingCircle(
	points
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;points : 윤곽선&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;6-볼록-껍질-매우매우-중요-&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;(6) 볼록 껍질 (매우매우 중요 !!!)&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선 볼록 껍질 계산 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501947280&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;hull = cv2.convexHull(
	points,
	clockwise = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;points : 윤곽선&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;clockwise : 방향, 검출된 볼록 껍질의 볼록점들의 인덱스 순서를 의미.. 참일경우 시계방향으로 정렬, 거짓일 경우 반시계방향으로 정렬한다.&lt;br /&gt;볼록 껍질 알고리즘은 O(NlogN) 시간 복잡도를 갖는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;스크랜스키(Sklansky)알고리즘&lt;/b&gt;을 이용해 입력된 좌표들의 볼록한 외곽을 찾는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;스크랜스키-알고리즘&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;스크랜스키 알고리즘&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byyZEp/btsJPDUFnOR/1N4oKrh61KYTMz7VgdWjlk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byyZEp/btsJPDUFnOR/1N4oKrh61KYTMz7VgdWjlk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byyZEp/btsJPDUFnOR/1N4oKrh61KYTMz7VgdWjlk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/byyZEp/btsJPDUFnOR/1N4oKrh61KYTMz7VgdWjlk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;330&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;스크린스키는 경계사각형의 정점(Vertex)을 검출한다. 위 그림에선 정점은 T, L, B, R이 된다.&lt;br /&gt;행당 정점은 볼록점으로 사용한다.&lt;br /&gt;볼록 껍질의 또 다른 볼록점들은 R1, R2, R3, R4영역에 존재하며, Q영역 내부에는 절대 존재하지 않는다 !!&lt;br /&gt;그러므로 우린 R 영역에서 볼록점들을 검출하게된다.&lt;br /&gt;R영역에도 수많은 윤곽점들이 존재하므로 여기서 볼록 껍질을 이루는 볼록점들을 선별하는 과정을 거처야한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;313&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KKOle/btsJRb3lMQK/3SciizhPfMTIKKhBIB2tR0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KKOle/btsJRb3lMQK/3SciizhPfMTIKKhBIB2tR0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KKOle/btsJRb3lMQK/3SciizhPfMTIKKhBIB2tR0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/KKOle/btsJRb3lMQK/3SciizhPfMTIKKhBIB2tR0/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;313&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;313&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;선별 과정으로 위 그림처럼,&lt;br /&gt;볼록점 시작이 i이며, 다음 번째 볼록점은 i + 1이 된다.&lt;br /&gt;만약 i가 T,L,B, R중 하나 즉, 정점 중 하나 일 경우, i + 1 번째 볼록점과 i + 2 번째 볼록점 를 검출하기 위해&lt;br /&gt;다음 조건으로 볼록점을 선택한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #333e4c; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;i + 2의 점이 A1영역에 있을경우, i + 2는 i + 1로 활용한다.&lt;/li&gt;
&lt;li&gt;i + 2의 점이 A2영역에 있을경우, i + 2점은 볼록점에서 제외한다.&lt;/li&gt;
&lt;li&gt;i + 2의 점이 A3영역에 있을경우, i + 2점을 볼록점으로 간주한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;만약 i가 L(정점)이라고 가정하면, A1 영역은 R1이고 A2 영역은 Q영역, A3영역은 R2영역이된다.&lt;br /&gt;이렇게 정점위치에 따라 조건영역이 바뀐다는 점을 알아야한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 id=&quot;7-윤곽선의-모멘트-매우-중요-&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;(7) 윤곽선의 모멘트 (매우 중요 !!!)&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이미지에서 모멘트란, 영상 픽셀 강도에 대한 특정한 가중평균(모멘트) 또는 일반적으로 어떤 물체의 고유한 특성이나 해석을 할 수 있는 기능&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이다.&lt;br /&gt;윤곽선에서 모멘트는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;공간 모멘트&lt;/b&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;중심 모멘트 ( + 정규화)&lt;/b&gt;가 있다.&lt;br /&gt;공간모멘트는 물체의 공간을 나타내는 모멘트로써, 출력시 물체의 최외각 가장자리를 나타내며&lt;br /&gt;중심모멘트는 물체의 중심을 나타내는 모멘트로써, 물체의 중심에 점을 찍어준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;281&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dd3OTq/btsJQFRnpzq/UCkup0T52OVGS4niBktbEk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dd3OTq/btsJQFRnpzq/UCkup0T52OVGS4niBktbEk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dd3OTq/btsJQFRnpzq/UCkup0T52OVGS4niBktbEk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdd3OTq%2FbtsJQFRnpzq%2FUCkup0T52OVGS4niBktbEk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;281&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;281&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선의 모멘트 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501955550&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;moments = cv2.moments(
	array,
	binaryImage = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;array : 윤곽선이나 이미지&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;binaryImage : 이진화 이미지, 입력된 array 매개변수가 이미지일 경우, 이미지의 픽셀값들을 이진화 처리할지 결정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;4-코너-검출&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;4. 코너 검출&lt;/h2&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;코너 검출은 입력이미지에서 코너점을 검출하는 알고리즘이다.&lt;br /&gt;다각형의 꼭지점을 검출하는 것으로 이해하기 쉬운데, 정확하게는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;트래킹(Tracking), 객체의 움직임을 추적하거나 관찰하는 것&lt;/b&gt;을 하기 좋은 지점을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;코너&lt;/b&gt;라 한다.&lt;br /&gt;여기서 코너 검출 알고리즘은 높은 도함수를 갖는 지점(가장 두드러지는 코너점)을 계산하고 분석해서 코너 정의에 만족하는 점을 반환한다.&lt;br /&gt;코너는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;지안보 시와 카를로 토마시의 특징 검출 알고리즘&lt;/b&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;해리스가 제안한 알고리즘&lt;/b&gt;을 활용해 검출할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;코너 검출 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501962483&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;corners = cv2.goodFeaturesToTrack(
	image,
	maxCorners,
	qualityLevel,
	minDistance,
	mask = None,
	blockSize = None,
	useHarrisDetector = None
	k = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;image : 입력이미지, 8비트 또는 최대 32비트 단일 채널 이미지만 입력가능&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;maxCorners : 코너 최댓값, 검출할 최대 코너의 수를 제한한다. 0이하값은 무제한으로 검출하겠다는 소리다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;qualityLevel : 코너 품질, 반환할 코너의 최소 품질을 설정, 코너 품질은 0.0 ~ 1.0 사이의 값을 할당할 수 있으며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;일반적으로 0.01 ~ 0.10 값을 사용한다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;예를 들어 코너품질이 0.01이면, 가장 좋은 코너의 강도가 1000이라하면, 1000 * 0.01 = 10이다. 10이하의 코너 강도를 갖는 코너는 무시한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;minDistance : 최소 거리, 검출된 코너들의 최소 근접거리를 의미한다. 설정된 최소 거리 이상값만 검출한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;mask : 입력이미지와 같은 차원을 갖는 이미지이며, 마스크 값이 0인곳은 코너를 계산하지않는다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;blockSize : 블록크기, 코너를 계산할때 고려하는 코너 주변 영역의 크기&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;useHarrisDetector : 해리스 코너 검출기, 참일시 해리스가 제안한 알고리즘을 사용하고, 거짓일시 지안보 시와 카를로가 제안한 알고리즘을 사용한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;k : 해리스 측정 계수, 해리스 알고리즘을 사용할때 할당하며 해리스 대각합의 감도 계수를 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;객체를 인식하기 위해서 코너 검출 알고리즘을 사용한다면, 더 정확한 코너점들을 필요로한다.&lt;br /&gt;정확한 위치좌표값을 계산하기위해서, 근사 계산을 통한 서브픽셀 세밀화를 진행한다.&lt;br /&gt;그러면 검출된 코너의 좌표가 (30, 45)로 나왔는데,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서브 픽셀 세밀화&lt;/b&gt;를 하면 (30.5, 45.6)으로 더 정확한 좌표위치를 반환시켜준다.&lt;br /&gt;코너 픽셀의 세밀화를 진행하면 검출된 코너점의 위치를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;보정&lt;/b&gt;해준다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;코너 픽셀 세밀화 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501970094&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cv2.cornerSubPix(
	image,
	corners,
	winSize,
	zeroZone,
	criteria
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;image : 입력이미지&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;corners : 코너 검출을 통해 얻어낸 정수 픽셀의 코너 위치를 담고있는 배열&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;winSize : 검출크기, 코너 위치를 중심으로 검출크기만큼 확장한다. 검출 크기의 인수값이 (n, n)일때 (n * 2 + 1, n * 2 + 1)의 크기로 영역을 검색한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;zeroZone : 제외크기, 검출영역에서 제외할 부분의 크기를 설정한다. 검출크기와 동일하게 작동하며, (-1, -1)일때에는 제외할 영역이 없음을 의미한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;criteria : 기준, 코너 픽셀 세밀화 반복 작업의 조건을 설정, 예를 들어 반복횟수가 10회, 정확도가 0.1인경우, 반복횟수가 10회를 달성하거나 정밀도가 0.1을 달성했을시 계산이 종료된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;코너 검출 및 코너 픽셀 세밀화 예제&lt;/p&gt;
&lt;pre id=&quot;code_1727501978460&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import cv2

src = cv2.imread(&quot;lego_p.jpeg&quot;)
dst = src.copy()

gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
corners = cv2.goodFeaturesToTrack(gray, 100, 0.01, 5, blockSize=3, useHarrisDetector=True, k=0.03)

for i in corners:
	cv2.circle(dst, tuple(i[0]), 3, (255, 0, 0), 5)

criteria = (cv2.TERM_CRITERIA_MAX_ITER + cv2.TERM_CRITERIA_EPS, 30, 0.01)
cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), criteria)

for i in corners:
	cv2.circle(dst, tuple(i[0]), 3, (0, 0, 255), 5)

cv2.imshow(&quot;dst&quot;, dst)
cv2.waitKey(0)
cv2.destroyAllWindows()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ck1TC8/btsJPLyhske/lDDU0bv5P3k0jpLKXVUKxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ck1TC8/btsJPLyhske/lDDU0bv5P3k0jpLKXVUKxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ck1TC8/btsJPLyhske/lDDU0bv5P3k0jpLKXVUKxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fck1TC8%2FbtsJPLyhske%2FlDDU0bv5P3k0jpLKXVUKxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;532&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;532&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>기술, 나의 공부를 공유합니다./[ML] Object Detection</category>
      <author>욘초</author>
      <guid isPermaLink="true">https://yonghyn.tistory.com/92</guid>
      <comments>https://yonghyn.tistory.com/92#entry92comment</comments>
      <pubDate>Sat, 28 Sep 2024 14:39:42 +0900</pubDate>
    </item>
    <item>
      <title>OpenCV 이미지 검출[1]_가장자리 검출, 윤곽선 검출 | 주요 특징점 검출, 이미지내의 객체를 검출한다</title>
      <link>https://yonghyn.tistory.com/91</link>
      <description>&lt;h1 id=&quot;opencv에서-제일-중요한-부분-이미지에서-특징점-검출-&quot; style=&quot;color: #333e4c; text-align: start;&quot;&gt;OpenCV에서 제일 중요한 부분, 이미지에서 특징점 검출 !!&lt;/h1&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;영상내 주요한 특징점 !! Feature Point를 검출하는 방법&lt;br /&gt;특징점이 존재하는 위치나 해당 특징점을 부각시켜준다.&lt;br /&gt;how??.. 바로!!&lt;br /&gt;픽셀의 색상강도, 연속성, 변화량, 의존성, 유사성, 임계점 등을 이용해&lt;br /&gt;특징인 가장자리(Edge), 윤곽선(Contour), 코나(Corner), 블록껍질, 모멘트(Moment), 직선, 원 등을 구분한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가장자리(Edge)&lt;/b&gt;검출은 픽셀의 그레이디언트의 상위 임계값과 하위임계값을 사용해 검출한다.&lt;br /&gt;픽셀의 연속성, 연결성등이 있어야하며 가장자리로 인식하지않으면 모두 제거한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;윤곽선(Contour)&lt;/b&gt;검출은 동일한 색상이나 비슷한 강도를 가진 연속 픽셀을 하나로 묶어서 처리한다.&lt;br /&gt;윤곽 검출을 토해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;모멘트&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;코너&lt;/b&gt;, 면적, 경계선, 블록껍질 등을 적용할 수 있다.&lt;/p&gt;
&lt;h2 id=&quot;1-가장자리edge-검출&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;1. 가장자리(Edge) 검출&lt;/h2&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;가장자리, 엣지는 흔히 알듯 객체의 가장 바깥 둘레를 의미한다.&lt;br /&gt;즉, 객체의 테두리이다.&lt;br /&gt;이미지에서 가장자리는 전경(Foreground)와 배경(Background)이 구분되는 지점이다.&lt;br /&gt;물체의 가장자리 안의 영역은 전경, 즉 해당 물체의 영역이고&lt;br /&gt;물체의 가장자리 밖의 영역은 배경, 즉 배경 또는 다른 물체의 영역인 셈이다.&lt;br /&gt;그리고 이런 전경과 배경 사이에서의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;밝기가 큰폭으로 변하는 지점&lt;/b&gt;이다.&lt;br /&gt;즉, 가장자리는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;픽셀의 밝기가 급변하는 곳&lt;/b&gt;으로 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vmasI/btsJQ5B7nHK/NrBlIH8H7N0Vij67SNMkqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vmasI/btsJQ5B7nHK/NrBlIH8H7N0Vij67SNMkqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vmasI/btsJQ5B7nHK/NrBlIH8H7N0Vij67SNMkqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvmasI%2FbtsJQ5B7nHK%2FNrBlIH8H7N0Vij67SNMkqK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;530&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;입력이미지에서 가장자리를 검출하기 위해선&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;미분&lt;/b&gt;을 진행한다.&lt;br /&gt;그러나 이미지는 샘플링과 양자화가 거친 데이터이므로&lt;br /&gt;밝기의 평균 변화율이 아닌&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;밝기의 순간 변화율&lt;/b&gt;을 구해야한다.&lt;br /&gt;그러므로 인접한 픽셀들의 차이를 구하며, 하나의 컨벌루션 연산이라 볼 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333e4c; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;1차 미분 형태 : 극댓값이나 극솟값이 가장자리&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;2차 미분 형태 : 극값이 아닌 제로 크로싱(기울기가 양수에서 음수로 변할 때 0을 갖는 값의 위치)&lt;br /&gt;픽셀의 밝기에 따른 미분이 진행된다는 점을 보면&lt;br /&gt;&lt;b&gt;노이즈&lt;/b&gt;에 매우 민감하게 작용하겠다는 것을 알 수 있다.&lt;br /&gt;그래서 노이즈를 제거하는 전처리를 갖고 가장자리를 검출한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;꼭 !!&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;기억하자,, 가장자리는 노이즈 제거를 전처리로 진행한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;(사진 추후 참조)&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;미분 형태의 가장자리 유형은 Step, Line, Ramp, Roof형태가 존재한다.&lt;br /&gt;Step Edge에서 노이즈를 제거하면 Ramp Edge가 된다.&lt;br /&gt;Line Edge에서 노이즈를 제거하면 Roof Edge가 된다.&lt;br /&gt;&lt;b&gt;가장 대표적인 가장자리 유형은 Step Edge와 Line Edge 이다.&lt;/b&gt;&lt;br /&gt;이런 Step과 Line Edge를 검출하는 방법으로는&lt;br /&gt;소벨 미분(Sobel),&lt;span&gt;&amp;nbsp;&lt;/span&gt;샤르 필터(Scharr),&lt;span&gt;&amp;nbsp;&lt;/span&gt;라플라시안(Laplacian),&lt;span&gt;&amp;nbsp;&lt;/span&gt;캐니 엣지(Canny)가 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여기서 중요하게 볼게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;소벨 미분&lt;/b&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;캐니 엣지&lt;/b&gt;이다.&lt;/p&gt;
&lt;h3 id=&quot;1-소벨-미분-sobel&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;1. 소벨 미분 (Sobel)&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;소벨 미분은 미분값을 구하는데 가장 많이 사용하는 기본적인 미분법이라 생각하면된다.&lt;/b&gt;&lt;br /&gt;앞서 말한 것처럼 인접한 픽셀들의 차이로 기울기(Gradient)의 크기를 구한다.&lt;br /&gt;이때 인접한 픽셀간의 계산을 위해 컨벌루션을 진행한다.&lt;br /&gt;그러므로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;커널&lt;/b&gt;이 필요한데, 소벨 미분은 이 커널을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;소벨 마스크&lt;/b&gt;로 명명하여&lt;br /&gt;사용해 미분을 하고있다.&lt;br /&gt;소벨 미분은 커널 내부의 모든 픽셀값의 합이 0이 되어야하며,&lt;br /&gt;3x3 ~ 31x31까지 커널 크기가 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caOn8H/btsJQlljuRt/C57E0xyNXoELgfQiuYXNk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caOn8H/btsJQlljuRt/C57E0xyNXoELgfQiuYXNk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caOn8H/btsJQlljuRt/C57E0xyNXoELgfQiuYXNk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaOn8H%2FbtsJQlljuRt%2FC57E0xyNXoELgfQiuYXNk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;278&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;소벨 마스크는 거의 모든 크기의 커널로 정의할 수 있으며 (3x3 ~ 31x31),&lt;br /&gt;모든 방향으로 가장자리 검출이 가능하다&lt;br /&gt;크기가 작은 커널은 노이즈에 민감하게 반응하며&lt;br /&gt;크기가 큰 커널은 노이즈에 덜 민감하게 반응한다.&lt;br /&gt;&lt;b&gt;소벨 마스크는 다른 마스크들에 비해 노이즈에 강한편이다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;소벨 연산 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501801977&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dst = cv2.Sobel(
	src,
	ddepth,
	dx,
	dy,
	ksize = None,
	scale = None,
	delta = None,
	borderType = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;src : 입력 이미지&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;ddepth : 출력 이미지의 정밀도, 대부분 16bit이상의 정밀도를 갖는다. 그이유는 입력이미지가 8bit의 정밀도를 갖게될 시에 미분하면 오버플로가 발생할 수 있다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;dx, dy : xorder와 yorder로 미분의 차수를 결정한다. 일반적으로 0, 1, 2의 값을 사용하며 둘의 합이 1 이상이되어야한다. 0은 해당방향으론 미분을 하지않음을 나타낸다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;ksize : 커널의 크기로, 최소 3부터 최대 31까지 가능하다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;scale : 비율,&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;delta : 오프셋, 비율 &amp;amp; 오프셋은 출력이미지를 반환하기적 적용, 8bit형태 출력이미지를 통해 미분값을 시각적으로 확인할 때 사용&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;bordetType : 테두리 외삽법&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;dx = 1, dy = 0, ksize = 3인 경우는 3x3 소벨 수직 마스크 형태를 의미한다.&lt;/p&gt;
&lt;h3 id=&quot;2-샤르-필터&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;2. 샤르 필터&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;샤르필터는 소벨 미분의 단점을 보완했다.&lt;br /&gt;소벨 미분은 커널의 크기가 작으면 노이즈의 영향으로 정확도가 떨어지는데, 정확히 3x3 소벨필터의 경우 기울기(Gradient)의 각도가 수평이나 수직에서 멀어질 수록 정확도가 떨어진다.&lt;br /&gt;이 부정확성을 해결하기위해서 샤르 필터를 사용하며&lt;br /&gt;샤르 필더는 소벨 필터보다 빠르고 정확하기 때문에&lt;br /&gt;만약 소벨 필터 3x3을 써야한다면,, 샤르필터 3x3을 쓴다.&lt;br /&gt;참고로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;샤르필터는 3x3크기의 커널만 존재한다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;샤르 연산 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501808408&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dst = cv2.Scharr(
	src,
	ddepth,
	dx,
	dy,
	scale = None,
	delta = None,
	borderType = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;모두 소벨 미분과 똑같은 매개변수이다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;차이는 샤르는 커널크기가 3x3으로 고정되어있어서, ksize가 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;3-라플라시안&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3. 라플라시안&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;라플라시안은 2차 미분의 형태이다.&lt;br /&gt;1차 미분은 주로 가장자리의 존재 여부를 알기위해 수행되고,&lt;br /&gt;2차 미분은 가장자리가 어두운부분에서 발생한 것인지 밝은 부분에서 발생한 것인지 확인할 수 있다.&lt;br /&gt;2차 미분 방식은 x축과 y축을 따라 2차 미분한 합을 의미 = 라플라시안은 x축, y축을 따라 2차 미분한 합을 의미한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;243&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L9iv5/btsJPKe5ZL3/mzDeCi7qzb5YhI18tY1HrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L9iv5/btsJPKe5ZL3/mzDeCi7qzb5YhI18tY1HrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L9iv5/btsJPKe5ZL3/mzDeCi7qzb5YhI18tY1HrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL9iv5%2FbtsJPKe5ZL3%2FmzDeCi7qzb5YhI18tY1HrK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;243&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;243&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;높은 값으로 둘러싸인 픽셀이나 커널보다 작은 얼룩은 양수를 최대화 하며, 낮은 값으로 둘러싸인 픽셀이나 커널보다 큰 얼룩은 음수를 최대화한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;라플라시안 연산 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501814523&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dst = cv2.Laplacian(
	src,
	ddepth,
	ksize,
	scale = None,
	delta = None,
	borderType = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;모두 기존 소벨 연산 함수에 쓰인 동일한 매개변수이고&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;ddepth(결과 이미지 정밀도)로는 cv2.CV_8U를 주로 사용한다.&lt;br /&gt;그 외에도 cv2.CV_16S, cv2.CV_64F 등이 있다. (정밀도가 높다)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;라플라시안 연산 함수는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;소벨 연산&lt;/b&gt;에 기반을 두고 있으므로,&lt;br /&gt;소벨 연산 함수의 매개변수 의미와 활용방식이 동일하다.&lt;br /&gt;차이점은 커널의 크기(ksize)가 소벨 미분 커널을 의미하며&lt;br /&gt;2차 미분 계산을 위해 샘플링 하는 영역의 크기가 다르다.&lt;br /&gt;ksize = 1인 경우 기본 라플라시안 마스크를 사용한다.&lt;/p&gt;
&lt;h3 id=&quot;4-캐니-엣지-canny&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;4. 캐니 엣지 (Canny)&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;라플라시안 필터방식을 캐니(사람)가 개선한 방식,&lt;br /&gt;x와 y에 대해 1차미분을 한 후, 네 방향으로 미분을 하는 것이다.&lt;br /&gt;네 방향으로 미분한 결과로 극댓값을 갖는 지점들이 가장자리가 되는 것이다.&lt;br /&gt;성능이 어마무시하며 노이즈에 민감하지않아&lt;br /&gt;&lt;b&gt;강력한 가장자리 검출 알고리즘&lt;/b&gt;으로 알려져 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;캐니 엣지 동작 순서&lt;/p&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;1 : 노이즈 제거를 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;가우시안 필터&lt;/b&gt;로 흐림효과 적용&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;2 : 기울기(Gradient) 값이 높은 지점을 검출 (&lt;b&gt;소벨 마스크&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;적용)&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;3 : 최댓값이 아닌 픽셀의 값을 0으로 변경(가장자리만 남기는 작업)&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;4 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;히스테리시스 임계값&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;적용&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;캐니 엣지는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;히스테리시스 임계값&lt;/b&gt;을 적용해 윤곽을 생성한다.&lt;br /&gt;임계값은 상위, 하위 임계값 두개가 존재하며&lt;br /&gt;픽셀이 상위 임계값보다 큰 기울기를 가지면 픽셀을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;가장자리&lt;/b&gt;로 인식하고&lt;br /&gt;픽셀이 하위 임계값보다 작은 기울기를 가지면 무시한다.&lt;br /&gt;그러면 상위 임계값 보단 작은데 하위 임계값 보다 큰 경우는 ??&lt;br /&gt;상위 임곗값에 연결된 경우만 가장자리 픽셀로 인식한다.&lt;br /&gt;예를 들어 상위 임계값이 200, 하위 임계값이 100이면&lt;br /&gt;230은 가장자리 픽셀로, 70은 무시하며, 130의 경우는 주변 인접한 픽셀들을 보고&lt;br /&gt;상위임계값과 연결되어있는 형태이면 가장자리로 인식하는 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;캐니 엣지 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501822447&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dst = cv2.Canny(
	src,
	threshold1,
	threshold2,
	apertureSize = None,
	L2gradient = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;src : 8bit 단일 채널 이미지만 입력이미지로 활용가능&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;threshold1 : 하위 임계값&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;threshold2 : 상위 임계값&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;apertureSize : 소벨 연산자 마스크 크기 (소벨 마스크 크기)&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;L2gradient : l2-norm으로 방향성 그레이디언트를 정확하게 계산할 건지, 정확성은 떨어지지만 속도가 더 빠른 l1-norm으로 계산할지 결정한다. True = L2 / False = L1&lt;br /&gt;&lt;b&gt;(아닐 수 있는 욘초 잡지식)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;인공지능에서 그레이디언트(기울기)를 구하는 방식은 총 2가지&lt;br /&gt;L2, L1방식이 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;캐니 엣지 활용&lt;/p&gt;
&lt;pre id=&quot;code_1727501829213&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import cv2
import numpy as np

src = cv2.imread(&quot;trump_card.jpg&quot;, cv2.IMREAD_GRAYSCALE)

dst = cv2.Canny(src, 100, 200, apertureSize=3, L2gradient=True)

cv2.imshow(&quot;dst&quot;, dst)
cv2.imshow(&quot;src&quot;, src)

cv2.waitKey(0)
cv2.destroyAllWindows()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;371&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BkyCV/btsJQlljuR9/6Brpurg2bk5R84PwwDwbp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BkyCV/btsJQlljuR9/6Brpurg2bk5R84PwwDwbp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BkyCV/btsJQlljuR9/6Brpurg2bk5R84PwwDwbp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBkyCV%2FbtsJQlljuR9%2F6Brpurg2bk5R84PwwDwbp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;371&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;371&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;보면 가장자리를 엄청 뚜렷하게 정확히 검출하는 것을 볼 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;2-윤곽선-검출&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;2. 윤곽선 검출&lt;/h2&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;가장자리 검출은 입력이미지에서 가장자리만 검출하는 것이지만, 검출된 객체들의 세그먼트(Segment : 서로 다른 두 점을 연결하는 가장 짧은 선)구성 요소가 구분돼있지 않아 어떤 형태인지 알 수 없다. 즉, 이미지에서 가장자리 검출은 했지만 그 가장자리가 어떤 객체의 가장자리인지,, 서로 구분할 수 있는 요소가 없다는 것인데.&lt;br /&gt;이를 윤곽선 검출에서 진행한다.&lt;br /&gt;윤곽선 검출은 전처리로 가장자리로 검출된 픽셀들을 대상으로 세그멘테이션(이미지에서 픽셀을 분류한뒤 그룹화)작업을 해준다.&lt;br /&gt;검출된 윤곽선은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;형상의 분석&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;물체 감지 및 인식&lt;/b&gt;에 가장 효과적인 방법이다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선 검출 과정에서는 검출하기 좋은 상태의 이미지를 갖고 진행하는 것이다.&lt;br /&gt;노이즈제거가 필수이며, 전처리로 가장자리 검출을 진행해야된다.&lt;br /&gt;그러고 나면&lt;span&gt;&amp;nbsp;&lt;/span&gt;윤곽선 검색 방법&lt;span&gt;&amp;nbsp;&lt;/span&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;근사 방법을 선택하는 것이다.&lt;br /&gt;윤곽선 검색 방법으로 윤곽점들의 세그먼테이션 방법(선을 이어주는 방식)을 선택할 수 있고,&lt;br /&gt;근사 방법으로 모든 윤곽선에 대한 윤곽점을 반환할 수 도있다.&lt;br /&gt;우리가 윤곽선에서 제일 중요하게 생각해야되는게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;계층 구조&lt;/b&gt;의 형태이다.&lt;/p&gt;
&lt;h3 id=&quot;계층-구조&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;계층 구조&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선 계층구조는 세그먼테이션이 어떻게 분류되었는가에대한 정보를 담고있다.&lt;br /&gt;즉, 물체안에 여러 가장자리 정보가 나온다면 물체의 세그먼테이션, 물체 안의 가장자리에대한 세그먼테이션들이 생겨난다.&lt;br /&gt;물체안의 윤곽선들을 분류해서 필요한 윤곽선들만 쓸 수 있게 하는게 계층 구조이다.&lt;br /&gt;어렵겠지만 이부분은 아래 설명을 더 보면 이해할 수 있을 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;계층 구조는 기본적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;트리(Tree) 구조&lt;/b&gt;의 형태이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;397&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Em20g/btsJPNisodj/gjcWpE4jPxWUkkqipGqET1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Em20g/btsJPNisodj/gjcWpE4jPxWUkkqipGqET1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Em20g/btsJPNisodj/gjcWpE4jPxWUkkqipGqET1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEm20g%2FbtsJPNisodj%2FgjcWpE4jPxWUkkqipGqET1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;397&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;397&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 그림에서 A 노드가 트리구조에서 최상위 노드인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;루트 노트&lt;/b&gt;라 하며,&lt;br /&gt;B와 C 노드의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;부모 노드 = A노드&lt;/b&gt;라 할 수 있다.&lt;br /&gt;그러면 A 노드한테 B와 C노드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자식 노드&lt;/b&gt;라 한다.&lt;br /&gt;자식노드가 없는 C노드의 경우에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;잎(leaf) 노드&lt;/b&gt;라 한다.&lt;br /&gt;잎노드가 아닌 모든 노드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;내부 노드&lt;/b&gt;라고도 한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선 계층구조에서 계층단계별 인덱스의 값을 구분해,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;다음 윤곽선&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이전 윤곽선&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자식 윤곽선&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;부모 윤곽선&lt;/b&gt;을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lRNER/btsJQn4xwth/AuplBghe3i47vnT335lXR0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lRNER/btsJQn4xwth/AuplBghe3i47vnT335lXR0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lRNER/btsJQn4xwth/AuplBghe3i47vnT335lXR0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlRNER%2FbtsJQn4xwth%2FAuplBghe3i47vnT335lXR0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;278&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;노드 0의 다음 윤곽선은 같은 레벨(최외각 윤곽선)에 있는 노드 2가 된다.&lt;br /&gt;이전 윤곽선은 존재하지않아 -1을 반환하며, 부모노드도 존재하지않아 -1을 반환, 자식 노드는 존재한다.&lt;br /&gt;이런 식으로 같은 레벨에 있는 노드끼리는 서로 이전, 다음 윤곽선으로 이어져있고,&lt;br /&gt;자식과 부모, 다음, 이전 윤곽선에 대해 존재유무에 따라 해당 노드번호 또는 -1을 반환한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 id=&quot;윤곽선-검출&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;윤곽선 검출&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선 검출 함수의 중요 매개변수는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;검색방법 과 근사방법&lt;/b&gt;이다.&lt;br /&gt;검색방법은 윤곽선의 계층 구조에 영향을 미치며,&lt;br /&gt;근사방법은 윤곽선들의 윤곽점 형태와 개수에 영향을 미친다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선 검출 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501838441&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;contours, hierarchy = cv2.findContours(
	image,
	mode,
	method,
	offset = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;contours : 검출된 윤곽선 (반환값)&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;hierarchy : 계층 구조 (반환값)&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;image : 입력이미지&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;mode : 검색방법, 어떤 계층구조의 형태를 사용할 것인지 결정 (아래 flag 참조)&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;method : 근사방법, 윤곽점 표시 방법 설정 (아래 flag 참조)&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;offset : 반환된 윤곽점들의 좌푯값에 이동할 값을 설정한다. 관심영역에서 윤곽선을 검출하거나 다른이미지에 표시하고자할때 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;mode flag&lt;/p&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.RETR_EXTERNAL&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 최외곽 윤곽선만 검색&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.RETR_LIST&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 모든 윤곽선 검출, 계층 구조 형성하지않음(모든 윤곽선을 동일한 레벨로 간주)&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.RETR_CCOMP&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 모든 윤곽선을 검출, 2단계 계층 구조로 구상화&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.RETR_TREE&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 모든 윤곽선을 검출하고 트리구조로 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;method flag&lt;/p&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.CHAIN_APPROX_NONE&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 검출된 모든 윤곽점 반환&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.CHAIN_APPROX_SIMPLE&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 수평,수직,대각선 부분을 압축해서 끝점만 반환&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.CHAIN_APPROX_TC89_KCOS&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: The-Chain 체인 근사 알고리즘 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 id=&quot;윤곽선-그리기&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;윤곽선 그리기&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다각형 그리기 함수를 활용해 윤곽선을 그린다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선 그리기 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501848671&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cv2.drawContours(
	image,
	contours,
	contourIdx,
	color,
	thickness = None,
	lineType = None,
	hierarchy = None,
	maxLevel = None,
	offset = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;image : 입력 이미지&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;contours : 윤곽선&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;contoursIdx : 윤곽선 번호, 설정하면 지정된 윤곽선만 그린다. 음수를 입력하면 모든 윤곽선을 그린다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;color : 색상&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;thickness : 두께&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;lineType : 선형 타입&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;hierarchy : 계층 구조, 윤곽선 검출 함수에서 반환된 계층 구조&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;maxLevel : 계증 구조 최대 레벨, 이미지에 그려질 윤곽선 계층 구조의 깊이 설정, 0으로 설정하면 최상위 레벨만 그려진다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;offset : 윤곽선 함수와 동일한 기능&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;윤곽선 검출 예제&lt;/p&gt;
&lt;pre id=&quot;code_1727501855823&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import cv2
import numpy as np

src = cv2.imread(&quot;trump_card_1.jpg&quot;)
dst = src.copy()

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))

gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 230, 255, cv2.THRESH_BINARY)
morp = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel, iterations=2)
image = cv2.bitwise_not(morp)

contours, hierarchy = cv2.findContours(image, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

cv2.drawContours(dst, contours, -1, (0,0,255), 3)
for i in range(len(contours)):
	cv2.putText(dst, str(i), tuple(contours[i][0][0]), cv2.FONT_HERSHEY_COMPLEX, 1.3, (255,0,0), 1)
	print(i, hierarchy[0][i])


cv2.imshow(&quot;dst&quot;, dst)
cv2.waitKey(0)
cv2.destroyAllWindows()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;502&quot; data-origin-height=&quot;529&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmR3W9/btsJPSYdYlT/zI1l6r02gOzSfylrXIjyo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmR3W9/btsJPSYdYlT/zI1l6r02gOzSfylrXIjyo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmR3W9/btsJPSYdYlT/zI1l6r02gOzSfylrXIjyo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmR3W9%2FbtsJPSYdYlT%2FzI1l6r02gOzSfylrXIjyo0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;502&quot; height=&quot;529&quot; data-origin-width=&quot;502&quot; data-origin-height=&quot;529&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #333e4c; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;노이즈 제거를 위해 이진화(threshold) 적용&lt;/li&gt;
&lt;li&gt;모폴로지 연산을 통해 스펙클 제거 (morphologyEx)&lt;/li&gt;
&lt;li&gt;반전연산(bitwise_not)을 수행해서 이미지 최외각(네모 윤곽선)을 검출하지 않게 설정&lt;/li&gt;
&lt;li&gt;그후 윤곽선 검출 및 윤곽선 그리기 함수를 적용 (findContours, drawContorus)&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>기술, 나의 공부를 공유합니다./[ML] Object Detection</category>
      <author>욘초</author>
      <guid isPermaLink="true">https://yonghyn.tistory.com/91</guid>
      <comments>https://yonghyn.tistory.com/91#entry91comment</comments>
      <pubDate>Sat, 28 Sep 2024 14:37:42 +0900</pubDate>
    </item>
    <item>
      <title>OpenCV 이미지 변환[2]_기하학적 변환, 모폴로지 변환 및 연산 | 특징 검출과 데이터 해석을 위한 이미지 전처리</title>
      <link>https://yonghyn.tistory.com/90</link>
      <description>&lt;h1 id=&quot;opencv에서-이미지-변환-이미지-전처리-작업&quot; style=&quot;color: #333e4c; text-align: start;&quot;&gt;OpenCV에서 이미지 변환, 이미지 전처리 작업&lt;/h1&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;앞절 이미지 변환[1]에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이미지 확대 &amp;amp; 축소&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이미지 크기 조절&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이미지 회전&lt;/b&gt;에 대한 내용을 다뤘으며,&lt;br /&gt;이미지 변환[2]에서는 영상처리 전처리에 있어서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;중요한&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;내용들로&lt;br /&gt;&lt;b&gt;기하학적 변환&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;모폴로지 변환&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;모폴로지 연산&lt;/b&gt;에 대해 배운다.&lt;/p&gt;
&lt;h2 id=&quot;4-기하학적-변환&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;4. 기하학적 변환&lt;/h2&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;기하학전 변환이란 것은 이미지를 인위적으로 변화시킨다는 것을 의미하고, 이미지를 구성하는 좌표들의 위치를 재배치한다고 볼 수 있다.&lt;br /&gt;기하학적 변환으론&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;아핀 변환&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;원근 변환&lt;/b&gt;이 있다.&lt;/p&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아핀 변환 : 2x3행렬을 사용, 행렬 곱셈에 벡터 합을 활용 표현 할 수 있는 변환&lt;br /&gt;원근 변환 : 3x3행렬을 사용, 호모그래피(뒤틀림, 오목함)로 모델링 할 수 있는 변환&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;아핀-변환-affine&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;아핀 변환 (Affine)&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;원래 아핀 변환 행렬의 기본 형태는 원근 변환과 동일한 3x3 행렬이다.&lt;br /&gt;하지만, 아핀 변환은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;선의 수평성을 유지&lt;/b&gt;하며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;변환 후에도 평행함을 유지&lt;/b&gt;한다.&lt;br /&gt;아핀 식은 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;305&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SNeUt/btsJQgqRJtj/hTkcBDJskkSLdYWmo62cU1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SNeUt/btsJQgqRJtj/hTkcBDJskkSLdYWmo62cU1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SNeUt/btsJQgqRJtj/hTkcBDJskkSLdYWmo62cU1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSNeUt%2FbtsJQgqRJtj%2FhTkcBDJskkSLdYWmo62cU1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;305&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;305&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;x1, y1은 변환 전 / x2, y2는 변환 후 이미지의 좌표값이다.&lt;br /&gt;변환을 하기 위해선 a00, a01, a10, a11, b0, b1 총 6개의 미지수를 알아야한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cU9Q4j/btsJRbbc5yl/pbp65JoX5IqO90omTo26W0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cU9Q4j/btsJRbbc5yl/pbp65JoX5IqO90omTo26W0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cU9Q4j/btsJRbbc5yl/pbp65JoX5IqO90omTo26W0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcU9Q4j%2FbtsJRbbc5yl%2Fpbp65JoX5IqO90omTo26W0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;322&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;아핀 변환은 임의의 3개 좌표를 매핑해서 기하학전 변환을 수행한다.&lt;br /&gt;예를 들어, 위 사진에서 a, b, c에 대한 임의의 좌표 a&amp;rsquo;와 b&amp;rsquo;, c&amp;rsquo;을 가지고&lt;br /&gt;&lt;b&gt;아핀 맵 행렬&lt;/b&gt;로 계산해서 아핀 변환을 수행한다.&lt;br /&gt;그러면 오른쪽 그림처럼 기하학적 변환이 발생한다.&lt;br /&gt;여기서 중요한게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;아핀 맵 행렬&lt;/b&gt;을 기존좌표와 임의의 좌표들을 가지고 만드는게 중요하다.&lt;br /&gt;아핀 변환은 6개의 미지수를 구하기위해 3개 픽셀 좌표를 재매핑해 아핀 맵 행렬로 계산하는 것을 의미한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;아핀 맵 행렬 생성 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501700820&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;M = cv2.getAffineTransform(
  src,
  dst
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src : 변환전 이미지의 좌표 3개&lt;br /&gt;dst : 변환후 이미지의 좌표 3개&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;아핀 변환 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501706916&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dst = cv2.warpAffine(
  src,
  M,
  dsize,
  dst = None,
  flags = None,
  borderMode = None,
  borderValue = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src : 입력 이미지&lt;br /&gt;M : 생성한 아핀 맵 행렬&lt;br /&gt;dsize : 출력 이미지 크기&lt;br /&gt;dst : 출력 이미지&lt;br /&gt;flags : 보간법&lt;br /&gt;borderMode : 테두리 외삽법,&lt;br /&gt;borderValue : 테두리 색상, 변환후 발생하는 빈 공간을 채울 색&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 id=&quot;원근-변환-perspective&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;원근 변환 (Perspective)&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;원근 변환은 앞서 말했다시피 3x3행렬이며, 아핀변환과 다른 점은&lt;br /&gt;수평성이 유지되지않는 다는 점이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MkvvY/btsJPgr8PTX/RRlVj0EuRjN6IokY16De4k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MkvvY/btsJPgr8PTX/RRlVj0EuRjN6IokY16De4k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MkvvY/btsJPgr8PTX/RRlVj0EuRjN6IokY16De4k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMkvvY%2FbtsJPgr8PTX%2FRRlVj0EuRjN6IokY16De4k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;368&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;368&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 식을 보면, 아핀과 다르게 세 번째 행의 값이 미지수 a20, a21, 1로 변해&lt;br /&gt;구해줘야할 미지수가 6개에서 8개로 늘어났다.&lt;br /&gt;추가된 2개의 미지수 a20, a21이 아핀과 원근의 차이점이 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4DWw2/btsJPBvXOcs/D4Iv5l0LF6P0SXRWl3ewjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4DWw2/btsJPBvXOcs/D4Iv5l0LF6P0SXRWl3ewjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4DWw2/btsJPBvXOcs/D4Iv5l0LF6P0SXRWl3ewjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4DWw2%2FbtsJPBvXOcs%2FD4Iv5l0LF6P0SXRWl3ewjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;300&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;원근 변환은 아핀 변환과 동일한 방법으로, 기존 좌표에서&lt;br /&gt;임의의 좌표 4개 a&amp;rsquo;, b&amp;rsquo;, c&amp;rsquo;, d&amp;rsquo;까지 이동한걸&lt;b&gt;원근 맵 행렬&lt;/b&gt;로 계산한 후,&lt;br /&gt;아핀 변환을 진행한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;원근 맵 행렬 생성 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501713622&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;M = cv2.getPerspectiveTransform(
  src,
  dst
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src : 변환전 이미지 좌표 4개&lt;br /&gt;dst : 변환후 이미지 좌표 4개&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;원근 변환 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501720076&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dst = cv2.warpPerspective(
  src,
  M,
  dsize,
  dst = None,
  flags = None,
  borderMode = None,
  borderValue = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;M : 아핀변환과 다른 행렬을 갖고있는 원근 맵 행렬이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 id=&quot;아핀-변환과-원근-변환-예제&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;아핀 변환과 원근 변환 예제&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;아핀 변환과 원근 변환&lt;/p&gt;
&lt;pre id=&quot;code_1727501727756&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import cv2
import numpy as np

src = cv2.imread(&quot;rena.png&quot;)
height , width, _ = src.shape

src_pst_pers = np.array([[0.0, 0.0], [width, 0.0], [width, height], [0.0, height]], dtype = np.float32)
dst_pst_pers = np.array([[50.0, 50.0], [200, 30.0], [width-80.0, height-50.0], [0.0, height-40.0]], dtype = np.float32)
src_pst_aff = np.array([[0.0, 0.0], [width, 0.0], [width, height]], dtype = np.float32)
dst_pst_aff = np.array([[50.0, 50.0], [200, 30], [width, height-50]], dtype = np.float32)
M_pers = cv2.getPerspectiveTransform(src_pst_pers, dst_pst_pers)
M_aff = cv2.getAffineTransform(src_pst_aff, dst_pst_aff)

dst_pers = cv2.warpPerspective(src, M_pers, (width, height), borderValue=(0,0,0,0))
dst_aff = cv2.warpAffine(src, M_aff, (width, height), borderValue=(0,0,0,0))

cv2.imshow(&quot;dst_pers&quot;, dst_pers)
cv2.imshow(&quot;dst_aff&quot;, dst_aff)

cv2.waitKey(0)
cv2.destroyAllWindows()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;329&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RJqZ6/btsJQT9H4o6/qY3OT7dkLdXGpJWfhUKK5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RJqZ6/btsJQT9H4o6/qY3OT7dkLdXGpJWfhUKK5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RJqZ6/btsJQT9H4o6/qY3OT7dkLdXGpJWfhUKK5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRJqZ6%2FbtsJQT9H4o6%2FqY3OT7dkLdXGpJWfhUKK5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;329&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;329&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;5-모폴로지-변환&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;5. 모폴로지 변환&lt;/h2&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;모폴로지 변환은 이미지를 형태학적 관점으로 접근한다.&lt;br /&gt;주로 영상 내 픽셀값 대체에 사용하는데.&lt;br /&gt;모폴로지 변환은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;노이즈 제거&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;요소 결합 및 분리&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;강도 피크 검출&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;등에 이용할 수 있다.&lt;br /&gt;단연,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;노이즈 제거&lt;/b&gt;할 수 있다는 점이 모폴로지 변환을 많이 사용하는 주 이유이다.&lt;br /&gt;기본적인 모폴로지 변환으로는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;팽창&lt;/b&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;침식&lt;/b&gt;이 있다.&lt;br /&gt;두개 모두 이미지와 커널의 컨벌루션 연산이며, 두개의 기본 연산을 기반으로&lt;br /&gt;복잡하고 다양한 모폴로지 연산을 구현할 수 있다.&lt;br /&gt;&lt;b&gt;모폴로지 변환은 전처리, 후처리과정에서 가장 많이 사용하는 변환&lt;/b&gt;이다.&lt;/p&gt;
&lt;h3 id=&quot;팽창&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;팽창&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;커널 영역 안에 존재하는 모든 픽셀의 값을 커널 내부의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;극대값 (local Maximum)&lt;/b&gt;으로 대체한다.&lt;br /&gt;&lt;b&gt;구조요소&lt;/b&gt;를 활용해 이웃한 픽셀을 최대값으로 대체한다.&lt;br /&gt;팽창 연산을 수행하면, 어두운 부분 줄어들고 밝은 부분은 늘어난다.&lt;br /&gt;커널의 크기와 반복 횟수에 따라 밝은 부분이 늘어나면서&lt;br /&gt;&lt;b&gt;스펙클(spackle)&lt;/b&gt;이 커지며 객체 내부의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;홀(holes)&lt;/b&gt;이 사라진다.&lt;br /&gt;&lt;b&gt;노이즈 제거 후 줄어든 크기를 복구할때&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;주로 사용한다.&lt;/p&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스펙클 : 반점, 얼룩 홀 : 입력 이미지에서 매핑을 수행하고 나온 결과 이미지에 생기는 빈 공간&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;침식&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;침식&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;커널 영역 안에 존재하는 모든 픽셀의 값을 커널 내부의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;극소값 (local Minimum)&lt;/b&gt;으로 대체한다.&lt;br /&gt;&lt;b&gt;구조요소&lt;/b&gt;를 활용해 이웃한 픽셀을 최소값으로 대체한다.&lt;br /&gt;침식 연산을 수행하면, 어두운 부분은 늘어나고 밝은 부분은 줄어든다.&lt;br /&gt;커널의 크기와 반복 횟수에 따라 어두운 부분이 늘어나면서&lt;br /&gt;&lt;b&gt;스펙클&lt;/b&gt;이 사라지고, 객체 내부의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;홀&lt;/b&gt;이 커진다.&lt;br /&gt;&lt;b&gt;노이즈 제거에 주로 사용한다&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;모폴로지 변환은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;커널의 크기&lt;/b&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;커널의 형태(구조 요소)&lt;/b&gt;에 영향을 크게 받는다.&lt;br /&gt;여기서 커널의 형태 즉, 구조요소에는 직사각형, 타원, 십자모양이 존재한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;구조 요소 생성 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501735039&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kernel = cv2.getStructuringElement(
  shape,
  ksize,
  anchor = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;shape : 커널의 형태 flag이다. 직사각형(Rect), 십자가(Cross), 타원(Ellipse)가 있다. 자세한건 아래 커널의 형태 flag에 나와있다.&lt;br /&gt;ksize : 커널의 크기&lt;br /&gt;anchor = None : 고정점은 모폴로지 함수에서 위치 할당이 가능하기에, 이 함수에선 필수 매개변수가 아니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;커널의 형태 flag, 구조요소 flag&lt;/p&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.MORPH_RECT&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 직사각형 형태, 커널 내부가 모두 1로 설정&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.MORPH_CROSS&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 십자가 형태, 커널 내부가 모두 1로 설정&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.MORPH_ELLIPSE&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 타원 형태, 커널의 높이와 너비를 축으로하고 커널 내부가 모두 1로 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;팽창함수와-침식함수&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;팽창함수와 침식함수&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;팽창 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501742679&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dst = cv2.dilate(
  src,
  kernel,
  anchor = None,
  iterations = None,
  borderType = None,
  borderValue = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;침식 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501748701&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dst = cv2.erode(
  src,
  kernel,
  anchor = None,
  iterations = None,
  borderType = None,
  borderValue = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src : 입력 이미지&lt;br /&gt;kernel : 입력 형태, 구조 요소&lt;br /&gt;anchor : 함수내에서 설정 가능&lt;br /&gt;iterations : 반복 횟수&lt;br /&gt;borderType : 테두리 외삽법&lt;br /&gt;borderValue : 테두리 색상&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;모폴로지 팽창 , 침식&lt;/p&gt;
&lt;pre id=&quot;code_1727501755177&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import cv2

src = cv2.imread(&quot;flower.jpg&quot;)

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3), anchor= (-1, -1))


dst_dilate = cv2.dilate(src, kernel, iterations=3)
dst_erode = cv2.erode(src, kernel, iterations=3)

cv2.imshow(&quot;src&quot;, src)
cv2.imshow(&quot;dst_dilate&quot;, dst_dilate)
cv2.imshow(&quot;dst_erode&quot;, dst_erode)
cv2.waitKey(0)
cv2.destroyAllWindows()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vD9OZ/btsJPpI9yV9/RSsQB9FpUclnaZqgDqXjZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vD9OZ/btsJPpI9yV9/RSsQB9FpUclnaZqgDqXjZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vD9OZ/btsJPpI9yV9/RSsQB9FpUclnaZqgDqXjZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvD9OZ%2FbtsJPpI9yV9%2FRSsQB9FpUclnaZqgDqXjZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;750&quot; height=&quot;210&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;210&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;6-모폴로지-연산&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;6. 모폴로지 연산&lt;/h2&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;모폴로지 연산은 모폴로지 변환의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;팽창&lt;/b&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;침식&lt;/b&gt;을 기본 연산으로 사용해&lt;br /&gt;만들 수 있는 복잡하고 다양한 연산을 말한다.&lt;br /&gt;이미지가 이진화되어있다면, 팽창과 침식만으로도 충분히 좋은 결과를 얻을 수 있지만.. 그레이스케일이나 다중채널 이미지의 경우 복잡한 연산을 필요로한다.&lt;br /&gt;그래서 그레이스케일과 다중채널 이미지의 처리를 위해 모폴로지 연산을 사용한다.&lt;/p&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;모폴로지 연산 함수&lt;/p&gt;
&lt;pre id=&quot;code_1727501762725&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dst = cv2.morphologyEx(
  src,
  op,
  kernel,
  anchor = None,
  iterations = None,
  borderType = None,
  borderValue = None
)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src : 입력이미지&lt;br /&gt;&lt;b&gt;op&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 연산자 flag&lt;br /&gt;kernel : 커널의 형태, 구조요소&lt;br /&gt;iterations : 반복 횟수&lt;br /&gt;borderType : 테두리 외삽법&lt;br /&gt;borderValue : 테두리 색상&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여기서 주의 깊게 봐야할 매개변수는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;op(연산자)&lt;/b&gt;이다.&lt;br /&gt;연산자는 모폴로지 변환 함수를 조합해 수행하는 복합연산자를 뜻한다.&lt;br /&gt;아래 플래그 정보가 있다.&lt;br /&gt;연산자 플래그&lt;/p&gt;
&lt;blockquote style=&quot;color: #90949a; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.MORPH_DILATE&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 팽창 연산&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.MORPH_ERODE&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 침식 연산&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.MORPH_OPEN&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 열림 연산, 침식 후 팽창&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.MORPH_CLOSE&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 닫힘 연산, 팽창 후 침식&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.MORPH_GRADIENT&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 모폴로지 그레이디언트, 팽창img - 침시img&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.MORPH_TOPHAT&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 탑햇 연산, 기본img - 열림img&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.MORPH_BLACKHAT&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 블랙햇 연산, 닫힘img - 기본img&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;cv2.MORPH_HITMISS&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 히트미스 연산, 모서리 검출&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;연산자&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;연산자&lt;/h2&gt;
&lt;h3 id=&quot;1-열림-연산--이미지에서-스펙클-제거&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;1. 열림 연산 | 이미지에서 스펙클 제거&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;팽창 연사자와 침식 연산자의 조합,&lt;br /&gt;침식 연산 적용 후 팽창 연산을 적용한다.&lt;br /&gt;&lt;b&gt;스펙클&lt;/b&gt;이 사라지고 객체의 크기는 원래대로 돌아온다.&lt;/p&gt;
&lt;h3 id=&quot;2-닫힘-연산--이미지에서-홀-제거&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;2. 닫힘 연산 | 이미지에서 홀 제거&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;팽창 연산자와 침식 연산자의 조합,&lt;br /&gt;팽창 연산 적용 후 침식 연산을 적용한다.&lt;br /&gt;&lt;b&gt;홀&lt;/b&gt;이 사라지면서 객체의 크기는 원래대로 돌아온다.&lt;/p&gt;
&lt;h3 id=&quot;3-그레이디언트-연산--객체의-가장자리&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3. 그레이디언트 연산 | 객체의 가장자리&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;팽창 연산자와 침식 연산자의 조합,&lt;br /&gt;팽창 연산자를 적용한 팽창img와 침식 연산자를 적용한 침식img를 각각 생성한 후 감산한다.&lt;br /&gt;팽창img - 침식img&lt;br /&gt;밝은 영역의 가장자리를 분리하며 그레이스케일 이미지가 가장 급변하는 곳에서 가장 높은 결과를 반환한다.&lt;/p&gt;
&lt;h3 id=&quot;4-탑햇-연산--열림-연산에서-사라질-요소-표시&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;4. 탑햇 연산 | 열림 연산에서 사라질 요소 표시&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;입력이미지와 열림 연산의 조합,&lt;br /&gt;입력이미지 - 열림적용 이미지&lt;br /&gt;입력이미지의 객체들이 제외되고 국소적으로 밝았던 부분들이 분리된다.&lt;br /&gt;열림 연산에서 사라질 기본 이미지의 요소(스펙클, 밝은 부분)들을 표시한다.&lt;/p&gt;
&lt;h3 id=&quot;5-블랙햇-연산--닫힘-연산에서-사라질-요소-표시&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;5. 블랙햇 연산 | 닫힘 연산에서 사라질 요소 표시&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;입력이미지와 닫힘 연산의 조합,&lt;br /&gt;입력이미지 - 닫힘적용 이미지&lt;br /&gt;입력이미지의 객체들이 제외되고 국소적으로 어두웠던 홀들이 분리된다.&lt;br /&gt;닫힘 연산에서 사라질 기본 이미지의 요소(홀)들을 표시한다.&lt;/p&gt;
&lt;h3 id=&quot;6-히트미스-연산--모서리corner검출-_-매우-중요-&quot; style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;6. 히트미스 연산 | 모서리(corner)검출 _ 매우 중요 !!!&lt;/h3&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;히트미스 연산은 다른 연산들과는 다르다.&lt;br /&gt;&lt;b&gt;단일 채널 이미지&lt;/b&gt;에서 활용하며, 주로 이진화 이미지에 적용한다.&lt;br /&gt;전경이나 배경 픽셀의 특정 패턴을 찾는데 사용하고, 구조요소 형태에 큰 영향을 받는다.&lt;br /&gt;히트미스 연산의 컨벌루션 연산의 커널은 내부 요소가 0 또는 1의 값만 의미가 있다.&lt;br /&gt;0은 해당 픽셀을 고려하지않음, 1은 해당 요소를 유지하겠다는 뜻이다.&lt;br /&gt;이 특성 덕분에 모서리를 검출 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;227&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7Ge6T/btsJQkmubBN/b1KbK2Fa7iVWSIsWGYjvD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7Ge6T/btsJQkmubBN/b1KbK2Fa7iVWSIsWGYjvD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7Ge6T/btsJQkmubBN/b1KbK2Fa7iVWSIsWGYjvD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7Ge6T%2FbtsJQkmubBN%2Fb1KbK2Fa7iVWSIsWGYjvD1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;540&quot; height=&quot;227&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;227&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333e4c; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이미지 전처리, 후처리로 주로 사용되는 모폴로지 변환, 연산에 대해 알아봤다.&lt;br /&gt;특히, 모서리 검출할때 주로 쓰인다는 hitmiss 연산 방식은 나중에 도움이 될 수 있을 것 같다.&lt;/p&gt;</description>
      <category>기술, 나의 공부를 공유합니다./[ML] Object Detection</category>
      <author>욘초</author>
      <guid isPermaLink="true">https://yonghyn.tistory.com/90</guid>
      <comments>https://yonghyn.tistory.com/90#entry90comment</comments>
      <pubDate>Sat, 28 Sep 2024 14:36:08 +0900</pubDate>
    </item>
  </channel>
</rss>