<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ralmyon 님의 블로그</title>
    <link>https://ralmyon.tistory.com/</link>
    <description>ralmyon 님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Thu, 21 May 2026 09:33:33 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>ralmyon</managingEditor>
    <item>
      <title>[영상처리 및 비전] Edge Detection 정리 - Gradient부터 Canny까지</title>
      <link>https://ralmyon.tistory.com/3</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 영상처리에서 가장 기본이 되면서도 중요한 주제인 &lt;b&gt;Edge Detection&lt;/b&gt;에 대해 다뤄보려 한다. Edge는 이미지에서 객체의 경계를 나타내는 핵심 정보이며, 컴퓨터 비전의 거의 모든 분야에서 출발점이 되는 개념이다. 이번 글에서는 edge가 무엇인지부터 시작해서, 어떻게 검출하는지, 그리고 Canny edge detector까지 차근차근 알아보자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Edge란 무엇인가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Edge는 이미지에서 픽셀 값이 급격하게 변하는 지점을 의미한다. 사람이 사물을 인식할 때 윤곽선만 보고도 그것이 무엇인지 파악할 수 있는 것처럼, edge는 이미지의 매우 효율적인 표현 방식이다. &lt;b&gt;픽셀 전체보다 훨씬 적은 양의 정보로 장면의 핵심을 담을 수 있는&lt;/b&gt; 강력한 feature인 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 이미지에서 edge는 왜 생기는 것일까? Edge는 다음 네 가지 요인에 의해 발생한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Depth discontinuity&lt;/b&gt; (깊이 불연속) &amp;mdash; 물체와 배경 사이의 거리 차이&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Surface normal discontinuity&lt;/b&gt; (표면 법선 불연속) &amp;mdash; 면의 방향이 꺾이는 부분&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Surface color discontinuity&lt;/b&gt; (표면 색상 불연속) &amp;mdash; 색이 바뀌는 부분&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Illumination discontinuity&lt;/b&gt; (조명 불연속) &amp;mdash; 그림자 경계 등&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, edge는 단순히 &quot;색이 바뀌는 곳&quot;이 아니라 다양한 물리적 원인으로 발생하는 신호인 셈이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Edge를 수학적으로 어떻게 정의할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지의 한 행을 가로로 잘라 intensity 값을 그래프로 그려보면, edge가 있는 지점에서 값이 급격하게 변한다. 이 &quot;급격한 변화&quot;를 수학적으로 어떻게 잡아낼 수 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정답은 &lt;b&gt;미분&lt;/b&gt;이다. 함수가 급격하게 변하는 지점은 곧 &lt;b&gt;1차 미분 값이 극값(extrema)을 가지는 지점&lt;/b&gt;이다. 따라서 이미지를 미분해서 그 결과가 큰 지점을 찾으면 그것이 바로 edge가 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 디지털 이미지를 어떻게 미분할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연속 함수와 달리 이미지는 픽셀 단위로 이산적(discrete)이다. 그래서 미분도 근사식으로 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;part;f&amp;part;x[x,y]&amp;asymp;F[x+1,y]&amp;minus;F[x,y]\frac{\partial f}{\partial x}[x, y] \approx F[x+1, y] - F[x, y]&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;part;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;part;&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;&amp;asymp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;F&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;&amp;minus;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;F&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 linear filter로 구현하면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;x방향 미분: &lt;span&gt;&lt;span&gt;Hx=[1,&amp;minus;1]H_x = [1, -1] &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&amp;minus;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;y방향 미분: &lt;span&gt;&lt;span&gt;Hy=[&amp;minus;1,1]TH_y = [-1, 1]^T &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&amp;minus;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 필터를 이미지에 적용하면 어떻게 될까? 검은 사각형 이미지에 &lt;span&gt;&lt;span&gt;HxH_x &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;를 적용하면 &lt;b&gt;수직 방향의 edge&lt;/b&gt;(좌우 경계)만 검출되고, &lt;span&gt;&lt;span&gt;HyH_y &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;를 적용하면 &lt;b&gt;수평 방향의 edge&lt;/b&gt;(상하 경계)만 검출되는 결과를 얻게 된다. 각 필터는 해당 방향의 변화량만 측정하기 때문이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. Image Gradient &amp;mdash; 방향과 크기를 모두 담다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x방향 변화량과 y방향 변화량을 함께 묶으면 &lt;b&gt;gradient vector&lt;/b&gt;가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nabla;f=[&amp;part;f&amp;part;x,&amp;part;f&amp;part;y]\nabla f = \left[\frac{\partial f}{\partial x}, \frac{\partial f}{\partial y}\right]&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;nabla;&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;part;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;part;&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;part;&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;part;&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 gradient vector는 &lt;b&gt;intensity가 가장 빠르게 증가하는 방향&lt;/b&gt;을 가리킨다. 그리고 두 가지 중요한 정보를 추출할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Edge의 강도(strength)&lt;/b&gt; &amp;mdash; gradient의 크기:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;∥&amp;nabla;f∥=(&amp;part;f&amp;part;x)2+(&amp;part;f&amp;part;y)2\|\nabla f\| = \sqrt{\left(\frac{\partial f}{\partial x}\right)^2 + \left(\frac{\partial f}{\partial y}\right)^2}&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;∥&amp;nabla;&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;∥&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;part;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;part;&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;part;&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;part;&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Edge의 방향&lt;/b&gt; &amp;mdash; gradient의 각도:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;theta;=tan⁡&amp;minus;1(&amp;part;f&amp;part;y/&amp;part;f&amp;part;x)\theta = \tan^{-1}\left(\frac{\partial f}{\partial y} \bigg/ \frac{\partial f}{\partial x}\right)&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;theta;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;tan&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;minus;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;part;&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;part;&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;part;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;part;&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 한 가지 짚고 넘어갈 점이 있다. Gradient 방향과 edge 방향은 &lt;b&gt;서로 수직&lt;/b&gt;이다. 직관적으로 생각해보면, 절벽이 있을 때 절벽이 뻗은 방향(edge)과 절벽을 가로질러 올라가는 방향(gradient)은 90도 차이가 난다. 이 관계는 뒤에 NMS에서도 핵심적으로 쓰인다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. Noise라는 복병&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이론은 깔끔하다. 그런데 실제 이미지에 그냥 미분을 적용하면 어떻게 될까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는 &lt;b&gt;참담하다&lt;/b&gt;. Noise가 조금만 있어도 미분 결과는 완전히 난장판이 된다. 이유는 간단하다. &lt;b&gt;미분은 변화량을 측정하는 연산&lt;/b&gt;이기 때문에, noise처럼 픽셀마다 작게 들쭉날쭉한 변화도 모두 신호로 잡아내 증폭시켜버린다. 결국 진짜 edge의 큰 변화가 noise의 작은 변화들 사이에 묻혀버리게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 어떻게 해결할 수 있을까?&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. Solution: Smooth First&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결책은 의외로 간단하다. &lt;b&gt;미분하기 전에 먼저 smoothing을 해서 noise를 죽이는 것&lt;/b&gt;이다. Gaussian filter로 이미지를 부드럽게 만든 뒤 미분하면, noise는 평균화되어 사라지고 진짜 edge만 깔끔한 봉우리로 남게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순서를 정리하면 이렇다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이미지 &lt;span&gt;&lt;span&gt;ff &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;에 Gaussian &lt;span&gt;&lt;span&gt;hh &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;를 conv &amp;rarr; &lt;span&gt;&lt;span&gt;f&amp;lowast;hf * h &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&amp;lowast;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; (smoothing)&lt;/li&gt;
&lt;li&gt;그 결과를 미분 &amp;rarr; &lt;span&gt;&lt;span&gt;ddx(f&amp;lowast;h)\frac{d}{dx}(f * h) &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&amp;lowast;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; (edge 검출)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 한 결과, noise가 없는 깔끔한 edge 신호를 얻을 수 있게 된다. 물론 부작용으로 edge도 살짝 뭉개지지만, noise에 묻혀 아예 못 찾는 것보다는 훨씬 낫다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. 핵심 트릭: Convolution의 Associative Property&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 매우 중요한 수학적 성질이 등장한다. &lt;b&gt;Differentiation 자체가 convolution이고, convolution은 결합법칙(associative)을 만족&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ddx(f&amp;lowast;h)=f&amp;lowast;ddxh\frac{d}{dx}(f * h) = f * \frac{d}{dx}h&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&amp;lowast;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&amp;lowast;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 왜 중요할까? 원래대로라면 smoothing 한 번, 미분 한 번 해서 conv를 두 번 해야 한다. 하지만 이 성질을 이용하면 &lt;b&gt;Gaussian을 미리 미분해둔 커널&lt;/b&gt;(&lt;span&gt;&lt;span&gt;ddxh\frac{d}{dx}h &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, 즉 &lt;b&gt;Derivative of Gaussian, DoG&lt;/b&gt;)을 만들어서 이미지에 한 번만 conv하면 된다. 결과는 똑같은데 계산은 절반이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 DoG 커널이 바로 뒤에 나올 Sobel operator의 기반이 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8. Sobel Operator&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Sobel operator는 Derivative of Gaussian의 가장 대표적인 근사 필터다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;sx=18[&amp;minus;101&amp;minus;202&amp;minus;101],sy=18[121000&amp;minus;1&amp;minus;2&amp;minus;1]s_x = \frac{1}{8}\begin{bmatrix} -1 &amp;amp; 0 &amp;amp; 1 \\ -2 &amp;amp; 0 &amp;amp; 2 \\ -1 &amp;amp; 0 &amp;amp; 1 \end{bmatrix}, \quad s_y = \frac{1}{8}\begin{bmatrix} 1 &amp;amp; 2 &amp;amp; 1 \\ 0 &amp;amp; 0 &amp;amp; 0 \\ -1 &amp;amp; -2 &amp;amp; -1 \end{bmatrix}&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;8&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;minus;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;minus;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;minus;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;8&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;minus;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;minus;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;minus;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 한 가지 주의할 점이 있다. 표준 Sobel 정의에서는 1/8 항을 생략하는 경우가 많은데, &lt;b&gt;edge detection 자체에는 영향이 없지만 정확한 gradient 값을 얻으려면 1/8 항이 반드시 필요&lt;/b&gt;하다. 단순히 edge 위치만 찾는다면 무시해도 되지만, gradient의 절대적 크기가 의미 있는 작업에서는 빼먹으면 안 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Sobel 필터를 적용하면 &lt;span&gt;&lt;span&gt;sxs_x &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;는 수직 edge를, &lt;span&gt;&lt;span&gt;sys_y &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;는 수평 edge를 검출하고, 둘의 magnitude를 합치면 모든 방향의 edge를 담은 gradient magnitude 이미지를 얻을 수 있게 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9. Laplacian of Gaussian (LoG)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지는 1차 미분 이야기였다. 그렇다면 2차 미분으로는 어떻게 edge를 찾을 수 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1차 미분이 edge에서 &lt;b&gt;peak&lt;/b&gt;를 만든다면, 2차 미분은 edge에서 &lt;b&gt;zero-crossing&lt;/b&gt;(부호가 바뀌는 0 지점)을 만든다. Step edge에 2차 미분을 적용하면 양수로 솟았다가 음수로 떨어지는데, 그 사이 0을 지나는 정확한 지점이 edge의 위치가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 사용하는 필터가 바로 **Laplacian of Gaussian (LoG)**이다. Gaussian으로 smoothing하면서 동시에 2차 미분을 수행하는 결합 필터로, 가운데가 음수이고 주변이 양수인 멕시칸 햇(mexican hat) 모양을 가진다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10. DoG와 LoG를 함께 쓰면?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 흥미로운 통찰이 등장한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Gradient magnitude(DoG 계열)가 크고, 2차 미분(LoG)이 0인 픽셀이 edge다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DoG만 쓰면 edge가 두껍게 검출되고, LoG만 쓰면 noise 영역에서도 zero-crossing이 생겨 false edge가 나온다. 그런데 둘을 AND로 결합하면 어떻게 될까? &lt;b&gt;두 조건을 모두 만족하는 픽셀&lt;/b&gt;만 남게 되어 매우 정확한 edge map을 얻을 수 있게 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;11. 그래도 남는 문제 &amp;mdash; Edge가 두껍다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gradient magnitude를 thresholding해서 얻은 edge 이미지를 자세히 보면, edge가 한 픽셀 두께가 아니라 &lt;b&gt;여러 픽셀에 걸쳐 두꺼운 띠&lt;/b&gt; 형태로 나타난다. 진짜 edge는 딱 한 줄이어야 하는데 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 어떻게 해결할 수 있을까?&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;12. Non-Maximum Suppression (NMS)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결책은 &lt;b&gt;Non-Maximum Suppression&lt;/b&gt;이다. 이름 그대로 &quot;최대값이 아닌 것은 억제한다&quot;는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원리는 이렇다. 각 픽셀에서 &lt;b&gt;gradient 방향을 따라 양옆 두 픽셀을 본다&lt;/b&gt;. 그리고 자기 자신이 그 셋 중 가장 큰 값이면 살리고, 아니면 0으로 만들어버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 gradient 방향으로 비교할까? 앞서 말했듯 edge는 gradient에 수직이다. 따라서 gradient 방향을 따라가면 edge를 가로지르는 셈이고, 그 단면에서 가장 뾰족한 봉우리(peak)만 남기면 edge가 1픽셀 두께로 얇아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 한 가지 문제가 있다. Gradient 방향이 정확히 수평이나 수직이 아니라면, 비교해야 할 두 픽셀이 격자 위에 정확히 놓여 있지 않다. 이 경우 주변 픽셀들의 값을 &lt;b&gt;interpolation&lt;/b&gt;(보간)해서 추정해야 한다. (이 부분은 다음 강의에서 자세히 다룰 예정이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NMS를 적용한 결과, 두꺼웠던 edge가 깔끔한 1픽셀 두께의 선으로 정리되는 효과(thinning)를 얻을 수 있게 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;13. Hysteresis Thresholding&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NMS로 edge를 얇게 만들었다고 끝이 아니다. 단일 threshold로 edge를 결정하면 또 다른 문제가 생긴다. Threshold를 높게 잡으면 진짜 edge의 약한 부분이 끊어지고, 낮게 잡으면 noise까지 edge로 잡힌다.&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;b&gt;두 개의 threshold를 사용하는 것&lt;/b&gt;이다. 이를 &lt;b&gt;hysteresis thresholding&lt;/b&gt;이라고 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;High threshold&lt;/b&gt; 이상 &amp;rarr; 확실한 edge로 인정 (시작점)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Low threshold ~ High threshold 사이&lt;/b&gt; &amp;rarr; &quot;약한 edge&quot;. 강한 edge와 연결되어 있으면 살리고, 아니면 버림&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Low threshold 미만&lt;/b&gt; &amp;rarr; 무조건 버림&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 강한 edge A에서 출발해서 따라가다가 약한 부분 C를 만났다면, C는 살려둔다. 반면 어디에도 연결되지 않고 혼자 떠 있는 약한 edge B는 noise로 간주해서 버린다. 이렇게 하면 진짜 edge의 약한 부분은 보존하면서 noise는 효과적으로 걸러낼 수 있게 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;14. 모든 걸 합치면 &amp;mdash; Canny Edge Detector&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 배운 모든 개념을 하나로 묶은 것이 바로 그 유명한 &lt;b&gt;Canny edge detector&lt;/b&gt;다. 1986년 J. Canny가 제안한 이 방법은 &lt;b&gt;지금까지도 컴퓨터 비전에서 가장 널리 쓰이는 edge detector&lt;/b&gt; 중 하나다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 파이프라인은 다음과 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Filter image with derivative of Gaussian&lt;/b&gt; &amp;mdash; DoG로 noise 제거하면서 gradient 계산&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Find magnitude and orientation of gradient&lt;/b&gt; &amp;mdash; gradient의 크기와 방향 계산&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Non-maximum suppression&lt;/b&gt; &amp;mdash; edge를 1픽셀 두께로 얇게&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Linking and thresholding (hysteresis)&lt;/b&gt; &amp;mdash; 두 threshold로 진짜 edge만 남기기&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Canny detector는 세 가지 파라미터에 의해 동작이 결정된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;span&gt;&amp;sigma;\sigma &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;sigma;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;: Gaussian blur의 폭&lt;/li&gt;
&lt;li&gt;High threshold&lt;/li&gt;
&lt;li&gt;Low threshold&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 &lt;span&gt;&lt;span&gt;&amp;sigma;\sigma &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;sigma;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;의 선택이 결과에 큰 영향을 미친다. &lt;b&gt;&lt;span&gt;&lt;span&gt;&amp;sigma;\sigma &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;sigma;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;가 작으면 작은 디테일까지 edge로 잡히고, &lt;span&gt;&lt;span&gt;&amp;sigma;\sigma &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;sigma;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;가 크면 큰 scale의 윤곽선만 검출&lt;/b&gt;되는 결과를 얻게 된다. 같은 이미지라도 &lt;span&gt;&lt;span&gt;&amp;sigma;=1\sigma=1 &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;sigma;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;과 &lt;span&gt;&lt;span&gt;&amp;sigma;=2\sigma=2 &lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;sigma;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;로 처리한 결과는 전혀 다른 느낌을 준다. 어떤 scale의 edge를 원하는지에 따라 적절히 조절해야 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;15. 마치며 &amp;mdash; 그리고 그 너머&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 살펴본 방법들은 모두 &lt;b&gt;수작업으로 설계된(hand-crafted) 필터&lt;/b&gt;에 기반한다. 그렇다면 최근에는 어떤 방식을 쓸까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘은 딥러닝 기반의 edge detection이 많이 사용된다. 2017년 발표된 CASENet 같은 모델은 ResNet 기반의 deep network로 &lt;b&gt;카테고리 정보까지 담은 semantic edge&lt;/b&gt;를 검출한다. 단순히 &quot;여기 edge가 있다&quot;가 아니라 &quot;여기는 building과 road의 경계다&quot;처럼 의미를 함께 출력하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 그렇다고 해서 Canny가 의미 없어진 건 아니다. Canny는 여전히 &lt;b&gt;빠르고, 학습 데이터가 필요 없으며, 해석 가능한&lt;/b&gt; 강력한 기본 도구다. 딥러닝 모델의 전처리나 후처리에 활용되기도 하고, 임베디드 환경처럼 연산 자원이 제한된 곳에서는 필수 도구로 쓰인다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅을 한 줄로 요약하면 이렇다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Edge는 이미지의 미분으로 찾을 수 있지만, noise를 다루기 위해 Gaussian smoothing과 결합한 DoG/LoG를 사용하고, NMS와 hysteresis thresholding을 거쳐 깔끔한 edge map을 얻는다. 이 모든 과정을 묶은 것이 Canny edge detector다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Edge detection은 영상처리의 가장 기본 주제이지만, 그 안에 미분, convolution, noise 처리, thresholding 등 핵심 개념들이 모두 녹아 있다. 이 파이프라인을 제대로 이해해두면 이후 feature detection, contour, segmentation 같은 주제로 넘어갈 때 훨씬 수월해질 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 포스팅에서는 NMS에서 잠깐 언급했던 &lt;b&gt;interpolation&lt;/b&gt;에 대해 더 자세히 다뤄볼 예정이다.&lt;/p&gt;</description>
      <author>ralmyon</author>
      <guid isPermaLink="true">https://ralmyon.tistory.com/3</guid>
      <comments>https://ralmyon.tistory.com/3#entry3comment</comments>
      <pubDate>Sat, 2 May 2026 23:55:00 +0900</pubDate>
    </item>
    <item>
      <title>영상처리 및 비전을 공부해보자 - Linear Algebra &amp;amp; Transformation(하)</title>
      <link>https://ralmyon.tistory.com/2</link>
      <description>&lt;h3 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size23&quot;&gt;개념3 - 이미지 왜곡(Image Warping)과 선형 변환(Linear Transformation)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;이전 글에서 이미지는 행렬이고, 픽셀은 위치 좌표와 색상 정보를 가진 벡터라고 설명하였다. 그렇다면 이미지를 돌리고, 키우고, 비트는 작업은 수학적으로 어떻게 일어날까? 이미지를 왜곡(Warping)한다는 것은 수많은 픽셀들의 원래 위치 좌표 &lt;span data-index-in-node=&quot;136&quot; data-math=&quot;(x, y)&quot;&gt;$(x, y)$&lt;/span&gt; 를 새로운 좌표 &lt;span data-index-in-node=&quot;152&quot; data-math=&quot;(x^{\prime}, y^{\prime})&quot;&gt;$(x^{\prime}, y^{\prime})$&lt;/span&gt; 로 이동시키는 과정을 의미한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;이때 이동된 새로운 좌표들은 원래 좌표들에 대한 &lt;b data-index-in-node=&quot;27&quot; data-path-to-node=&quot;8&quot;&gt;선형 방정식(Linear equations)&lt;/b&gt; 으로 다음과 같이 묘사될 수 있다.&lt;/p&gt;
&lt;div data-path-to-node=&quot;9&quot;&gt;
&lt;div data-math=&quot;{x^{\prime}} = a_{00} x + a_{01} y + a_{02}&quot;&gt;$${x^{\prime}} = a_{00} x + a_{01} y + a_{02}$$&lt;/div&gt;
&lt;/div&gt;
&lt;div data-path-to-node=&quot;10&quot;&gt;
&lt;div data-math=&quot;{y^{\prime}} = a_{10} x + a_{11} y + a_{12}&quot;&gt;$${y^{\prime}} = a_{10} x + a_{11} y + a_{12}$$&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size20&quot;&gt;1. 선형성(Linearity)의 수학적 유도와 조건&lt;/h4&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;어떤 함수가 &lt;b data-index-in-node=&quot;7&quot; data-path-to-node=&quot;12&quot;&gt;선형(Linear)&lt;/b&gt; 이라고 불리기 위해서는 &lt;b data-index-in-node=&quot;31&quot; data-path-to-node=&quot;12&quot;&gt;가산성(Additivity)&lt;/b&gt; 과 &lt;b data-index-in-node=&quot;49&quot; data-path-to-node=&quot;12&quot;&gt;동차성(Homogeneity)&lt;/b&gt; 이라는 두 가지 성질을 만족해야 한다. 픽셀 변환 식 &lt;span data-index-in-node=&quot;96&quot; data-math=&quot;x^{\prime} = a x + b y + c * 1&quot;&gt;$x^{\prime} = a x + b y + c * 1$&lt;/span&gt; 을 예로 들어 이를 증명해 보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;13&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,0,0&quot;&gt;가산성 (Additivity):&lt;/b&gt; 두 입력 벡터의 합에 대한 결과가 각각의 결과의 합과 같아야 한다. 만약 좌표 &lt;span data-index-in-node=&quot;62&quot; data-math=&quot;(x, y, 1)&quot;&gt;$(x, y, 1)$&lt;/span&gt; 에 &lt;span data-index-in-node=&quot;74&quot; data-math=&quot;(z, 0, 0)&quot;&gt;$(z, 0, 0)$&lt;/span&gt; 을 더한 &lt;span data-index-in-node=&quot;89&quot; data-math=&quot;(x+z, y, 1)&quot;&gt;$(x+z, y, 1)$&lt;/span&gt; 을 입력으로 넣는다면, 결과는 &lt;span data-index-in-node=&quot;118&quot; data-math=&quot;a(x+z) + by + c&quot;&gt;$a(x+z) + by + c$&lt;/span&gt; 가 되어 기존 결과 &lt;span data-index-in-node=&quot;145&quot; data-math=&quot;x^{\prime}&quot;&gt;$x^{\prime}$&lt;/span&gt; 에 &lt;span data-index-in-node=&quot;158&quot; data-math=&quot;a z&quot;&gt;$a z$&lt;/span&gt; 가 더해진 &lt;span data-index-in-node=&quot;168&quot; data-math=&quot;x^{\prime} + z^{\prime}&quot;&gt;$x^{\prime} + z^{\prime}$&lt;/span&gt; 형태가 된다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,1,0&quot;&gt;동차성 (Homogeneity):&lt;/b&gt; 입력에 상수 &lt;span data-index-in-node=&quot;26&quot; data-math=&quot;s&quot;&gt;$s$&lt;/span&gt; 를 곱하면 결과도 &lt;span data-index-in-node=&quot;38&quot; data-math=&quot;s&quot;&gt;$s$&lt;/span&gt; 배가 되어야 한다. 입력 좌표에 &lt;span data-index-in-node=&quot;58&quot; data-math=&quot;s&quot;&gt;$s$&lt;/span&gt; 를 곱한 &lt;span data-index-in-node=&quot;65&quot; data-math=&quot;s * (x, y, 1)&quot;&gt;$s * (x, y, 1)$&lt;/span&gt; 을 넣으면 결과 역시 &lt;span data-index-in-node=&quot;91&quot; data-math=&quot;s x^{\prime}&quot;&gt;$s x^{\prime}$&lt;/span&gt; 이 되어 이 조건을 만족한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;이 식을 자세히 보면 우리가 익히 아는 &lt;b data-index-in-node=&quot;22&quot; data-path-to-node=&quot;14&quot;&gt;벡터의 내적(Dot product)&lt;/b&gt; 과 형태가 같다.&lt;/p&gt;
&lt;div data-path-to-node=&quot;15&quot;&gt;
&lt;div data-math=&quot;x^{\prime} = \begin{bmatrix} a &amp;amp; b &amp;amp; c \end{bmatrix} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}&quot;&gt;$$x^{\prime} = \begin{bmatrix} a &amp;amp; b &amp;amp; c \end{bmatrix} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}$$&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;이를 &lt;span data-index-in-node=&quot;3&quot; data-math=&quot;y^{\prime}&quot;&gt;$y^{\prime}$&lt;/span&gt; 까지 확장하면 다음과 같은 행렬 곱셈 형태가 완성된다.&lt;/p&gt;
&lt;div data-path-to-node=&quot;17&quot;&gt;
&lt;div data-math=&quot;\begin{bmatrix} x^{\prime} \\ y^{\prime} \end{bmatrix} \equiv \begin{bmatrix} a_{00} &amp;amp; a_{01} &amp;amp; a_{02} \\ a_{10} &amp;amp; a_{11} &amp;amp; a_{12} \end{bmatrix} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}&quot;&gt;$$\begin{bmatrix} x^{\prime} \\ y^{\prime} \end{bmatrix} \equiv \begin{bmatrix} a_{00} &amp;amp; a_{01} &amp;amp; a_{02} \\ a_{10} &amp;amp; a_{11} &amp;amp; a_{12} \end{bmatrix} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}$$&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size20&quot;&gt;2. 동차 좌표계(Homogeneous Coordinates)의 비밀&lt;/h4&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;위의 식에서 좌표 뒤에 1 을 붙이는 이유는 무엇일까? 이동 변환( &lt;span data-index-in-node=&quot;38&quot; data-math=&quot;a_{02}, a_{12}&quot;&gt;$a_{02}, a_{12}$&lt;/span&gt; )은 일반적인 &lt;span data-index-in-node=&quot;61&quot; data-math=&quot;2 \times 2&quot;&gt;$2 \times 2$&lt;/span&gt; 행렬 곱셈만으로는 표현할 수 없고 반드시 '더하기( &lt;span data-index-in-node=&quot;101&quot; data-math=&quot;+b&quot;&gt;$+b$&lt;/span&gt; )' 항이 따로 붙어야 한다. 하지만 좌표계에 1차원을 추가하여 &lt;span data-index-in-node=&quot;140&quot; data-math=&quot;(x, y, 1)&quot;&gt;$(x, y, 1)$&lt;/span&gt; 로 표현하면, 이동 변환까지 포함하여 모든 변환을 단 하나의 행렬 곱셈으로 통합할 수 있다. 이를 &lt;b data-index-in-node=&quot;205&quot; data-path-to-node=&quot;19&quot;&gt;동차 좌표계&lt;/b&gt; 라고 부른다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;20&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 정리하면 여러 단계의 변환을 하나의 행렬로 &lt;b data-index-in-node=&quot;28&quot; data-path-to-node=&quot;20&quot;&gt;축소(Reduce)&lt;/b&gt; 할 수 있다는 엄청난 장점이 생긴다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;21&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1단계 변환: &lt;span data-index-in-node=&quot;8&quot; data-math=&quot;Y = A X&quot;&gt;$Y = A X$&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;2단계 변환: &lt;span data-index-in-node=&quot;8&quot; data-math=&quot;Z = C Y&quot;&gt;$Z = C Y$&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;최종 변환: &lt;span data-index-in-node=&quot;7&quot; data-math=&quot;Z = C (A X) = (CA) X = E X&quot;&gt;$Z = C (A X) = (CA) X = E X$&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;즉, 아무리 복잡한 이미지 변형 과정이라도 결국 하나의 &lt;span data-index-in-node=&quot;31&quot; data-math=&quot;3 \times 3&quot;&gt;$3 \times 3$&lt;/span&gt; 행렬 &lt;span data-index-in-node=&quot;45&quot; data-math=&quot;E&quot;&gt;$E$&lt;/span&gt; 만 곱하면 끝나는 셈이다.&lt;/p&gt;
&lt;h4 data-path-to-node=&quot;23&quot; data-ke-size=&quot;size20&quot;&gt;3. 주요 선형 변환 행렬 카탈로그&lt;/h4&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;실제 컴퓨터 비전에서 사용하는 대표적인 변환 행렬들의 수식은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;25&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,0,0&quot;&gt;크기 조절 (Scale):&lt;/b&gt; 가로 배율 &lt;span data-index-in-node=&quot;21&quot; data-math=&quot;W&quot;&gt;$W$&lt;/span&gt; , 세로 배율 &lt;span data-index-in-node=&quot;31&quot; data-math=&quot;H&quot;&gt;$H$&lt;/span&gt; 만큼 늘리거나 줄인다.&lt;/li&gt;
&lt;li data-path-to-node=&quot;25,0,1&quot;&gt;
&lt;div data-math=&quot;\begin{bmatrix} x^{\prime} \\ y^{\prime} \end{bmatrix} = \begin{bmatrix} W &amp;amp; 0 \\ 0 &amp;amp; H \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} + \begin{bmatrix} 0 \\ 0 \end{bmatrix}&quot;&gt;$$\begin{bmatrix} x^{\prime} \\ y^{\prime} \end{bmatrix} = \begin{bmatrix} W &amp;amp; 0 \\ 0 &amp;amp; H \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} + \begin{bmatrix} 0 \\ 0 \end{bmatrix}$$&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,1,0&quot;&gt;회전 (Rotate):&lt;/b&gt; 원점을 중심으로 &lt;span data-index-in-node=&quot;22&quot; data-math=&quot;\theta&quot;&gt;$\theta$&lt;/span&gt; 만큼 회전시킨다.&lt;/li&gt;
&lt;li data-path-to-node=&quot;25,1,1&quot;&gt;
&lt;div data-math=&quot;\begin{bmatrix} x^{\prime} \\ y^{\prime} \end{bmatrix} = \begin{bmatrix} \cos \theta &amp;amp; \sin \theta \\ -\sin \theta &amp;amp; \cos \theta \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} + \begin{bmatrix} 0 \\ 0 \end{bmatrix}&quot;&gt;$$\begin{bmatrix} x^{\prime} \\ y^{\prime} \end{bmatrix} = \begin{bmatrix} \cos \theta &amp;amp; \sin \theta \\ -\sin \theta &amp;amp; \cos \theta \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} + \begin{bmatrix} 0 \\ 0 \end{bmatrix}$$&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,2,0&quot;&gt;기울임 (Shear):&lt;/b&gt; 이미지를 한쪽 방향으로 민다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;25,2,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;x 방향 기울임: &lt;span data-index-in-node=&quot;10&quot; data-math=&quot;\begin{bmatrix} 1 &amp;amp; \tan \phi \\ 0 &amp;amp; 1 \end{bmatrix}&quot;&gt;$\begin{bmatrix} 1 &amp;amp; \tan \phi \\ 0 &amp;amp; 1 \end{bmatrix}$&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;y 방향 기울임: &lt;span data-index-in-node=&quot;10&quot; data-math=&quot;\begin{bmatrix} \tan \psi &amp;amp; 0 \\ 1 &amp;amp; 1 \end{bmatrix}&quot;&gt;$\begin{bmatrix} \tan \psi &amp;amp; 0 \\ 1 &amp;amp; 1 \end{bmatrix}$&lt;/span&gt; (또는 유사한 형태)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,3,0&quot;&gt;반전 (Flip):&lt;/b&gt; 축을 기준으로 뒤집는다. 가로 반전 행렬의 첫 항은 &lt;span data-index-in-node=&quot;40&quot; data-math=&quot;-1&quot;&gt;$-1$&lt;/span&gt; , 세로 반전은 &lt;span data-index-in-node=&quot;52&quot; data-math=&quot;y&quot;&gt;$y$&lt;/span&gt; 관련 항이 &lt;span data-index-in-node=&quot;60&quot; data-math=&quot;-1&quot;&gt;$-1$&lt;/span&gt; 이 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-path-to-node=&quot;26&quot; data-ke-size=&quot;size20&quot;&gt;4. 구현의 핵심: 역변환(Inverse Transform)&lt;/h4&gt;
&lt;p data-path-to-node=&quot;27&quot; data-ke-size=&quot;size16&quot;&gt;이미지를 변환할 때 원본 좌표를 새 좌표로 보내는 방식(Forward mapping)을 쓰면 픽셀 사이에 빈틈이 생겨 구멍이 뚫린 것처럼 보일 수 있다. 이를 해결하기 위해 실제 구현에서는 &lt;b data-index-in-node=&quot;106&quot; data-path-to-node=&quot;27&quot;&gt;역변환&lt;/b&gt; 방식을 사용한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;28&quot; data-ke-size=&quot;size16&quot;&gt;즉, 결과 이미지의 모든 픽셀 좌표 &lt;span data-index-in-node=&quot;20&quot; data-math=&quot;(x^{\prime}, y^{\prime})&quot;&gt;$(x^{\prime}, y^{\prime})$&lt;/span&gt; 에 대해 &lt;b data-index-in-node=&quot;50&quot; data-path-to-node=&quot;28&quot;&gt;역행렬&lt;/b&gt; ( &lt;span data-index-in-node=&quot;56&quot; data-math=&quot;A^{-1}&quot;&gt;$A^{-1}$&lt;/span&gt; ) 을 곱하여 &quot;이 픽셀은 원본의 어디에서 왔는가?&quot;를 역추적해 값을 가져오는(Fetch) 방식이다. 이 과정 덕분에 선형 변환이 적용된 이미지가 깨지지 않고 부드럽게 출력될 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;29&quot; data-ke-size=&quot;size16&quot;&gt;이러한 수학적 원리를 이해하면, 단순히 필터를 입히는 수준을 넘어 실시간으로 피사체의 구도를 분석하거나 카메라 앵글을 보정하는 고도화된 비전 서비스를 설계할 수 있는 기초 체력이 길러진다.&lt;/p&gt;</description>
      <author>ralmyon</author>
      <guid isPermaLink="true">https://ralmyon.tistory.com/2</guid>
      <comments>https://ralmyon.tistory.com/2#entry2comment</comments>
      <pubDate>Sat, 11 Apr 2026 01:13:33 +0900</pubDate>
    </item>
    <item>
      <title>영상처리 및 비전을 공부해보자 - Linear Algebra &amp;amp; Transformation(상)</title>
      <link>https://ralmyon.tistory.com/1</link>
      <description>&lt;h3 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size23&quot;&gt;개념1 - 이미지 처리에 선형대수학(Linear algebra)가 왜 필요할까?&lt;/h3&gt;
&lt;h3 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size23&quot;&gt;1. 컴퓨터가 이미지를 인식하는 방법: 행렬(Matrix)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;우리가 보는 이미지는 연속적인 시각 정보 같지만, 컴퓨터는 이를 숫자의 배열인 행렬(Matrix)로 인식한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;기본적으로 흑백(Gray-level) 이미지는 2차원 행렬로 표현된다. 하지만 우리가 일상적으로 보는 컬러 이미지는 Red, Green, Blue 세 가지 색상의 조합으로 이루어져 있다. 즉, 각 픽셀이 &lt;span data-index-in-node=&quot;117&quot; data-math=&quot;[R, G, B]&quot;&gt;[R, G, B]&lt;/span&gt; 라는 3개의 값을 가지게 되며, 이를 수학적으로는 3개의 채널을 가진 행렬(또는 3차원 Tensor)로 표현하여 이미지를 컬러감 있게 볼 수 있는 것이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;결국 &quot;이미지 = 행렬&quot;이기 때문에, 이미지를 분석하고 처리하기 위해서는 행렬과 벡터를 다루는 선형대수학이 필수적인 도구가 된다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size23&quot;&gt;2. 픽셀과 벡터(Vector), 그리고 선형 변환(Linear Transformation)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;이미지를 구성하는 최소 단위인 픽셀(Pixel)을 다룰 때, 우리는 벡터(Vector)라는 개념을 적극 활용한다. 픽셀은 크게 두 가지 관점에서 벡터로 표현될 수 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,0,0&quot;&gt;위치 좌표로서의 벡터:&lt;/b&gt; 픽셀의 위치는 2차원 공간 상의 좌표 &lt;span data-index-in-node=&quot;34&quot; data-math=&quot;(x, y)&quot;&gt;(x, y)&lt;/span&gt;로 표현된다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,1,0&quot;&gt;색상 정보로서의 벡터:&lt;/b&gt; 앞서 말한 컬러 정보 &lt;span data-index-in-node=&quot;25&quot; data-math=&quot;[R, G, B]&quot;&gt;[R, G, B]&lt;/span&gt; 역시 1D array 형태의 벡터이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;우리가 이미지를 회전시키거나, 크기를 줄이거나, 위치를 이동시키는 등의 작업을 할 때, 수학적으로는 픽셀의 &lt;span data-index-in-node=&quot;60&quot; data-math=&quot;(x, y)&quot;&gt;(x, y)&lt;/span&gt; 좌표 벡터에 특정 행렬을 곱하여 새로운 좌표로 보내는 작업을 수행한다. 이를 &lt;b&gt;선형 변환(Linear Transformation)&lt;/b&gt;이라고 부르며, 이미지 처리의 본질은 결국 수많은 픽셀 벡터들을 계산하고 변환하는 과정이다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;3. 벡터의 특징과 주요 연산&lt;/h3&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;선형대수학에서 벡터(Vector)는 1개 이상의 숫자로 구성된 1차원 배열(1D array)을 의미하며, 공간상에서 크기(Magnitude)와 방향(Direction)을 가진다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;벡터 간의 곱셈 연산은 대표적으로 두 가지가 있으며, 결과값의 형태에 따라 명확한 차이가 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,0,0&quot;&gt;내적 (Inner Product / Dot Product)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,0,1,0,0&quot;&gt;특징:&lt;/b&gt; 두 벡터를 연산한 결과로 &lt;b data-index-in-node=&quot;18&quot; data-path-to-node=&quot;16,0,1,0,0&quot;&gt;단 하나의 스칼라(Scalar) 값&lt;/b&gt;이 나온다.&lt;/li&gt;
&lt;li&gt;주로 두 벡터가 얼마나 유사한 방향을 향하고 있는지(유사도)를 구할 때 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,0&quot;&gt;외적 (Cross Product)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,1,0,0&quot;&gt;특징:&lt;/b&gt; 두 벡터를 연산한 결과로 &lt;b&gt;새로운 벡터(Vector)&lt;/b&gt;가 나온다.&lt;/li&gt;
&lt;li&gt;주로 두 벡터가 이루는 평면에 수직인 법선 벡터를 구할 때 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,2,0&quot;&gt;공통점:&lt;/b&gt; 두 연산 모두 입력(Input)으로는 동일한 크기(Size)를 가진 2개의 벡터가 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size23&quot;&gt;4. 수학 기호 표기법 (Notation) 정리&lt;/h3&gt;
&lt;p data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;논문이나 전공 서적에서 수학 기호를 표기할 때는 다음과 같은 규칙을 따른다. 이를 알아두면 수식을 읽는 데 큰 도움이 된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;19&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,0,0&quot;&gt;스칼라 (Scalar):&lt;/b&gt; 이탤릭체 소문자 (예: &lt;span data-index-in-node=&quot;27&quot; data-math=&quot;x, y, a&quot;&gt;&lt;i&gt;x&lt;/i&gt;, &lt;i&gt;y&lt;/i&gt;, &lt;i&gt;a&lt;/i&gt;&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,1,0&quot;&gt;벡터 (Vector):&lt;/b&gt; 볼드체 소문자, 이탤릭체 사용 안 함 (예: x, y, v)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,2,0&quot;&gt;행렬 (Matrix) 및 텐서 (Tensor):&lt;/b&gt; 볼드체 대문자, 이탤릭체 사용 안 함 (예: X, A, W)&lt;/li&gt;
&lt;li&gt;inner prodcut의 출력 : &lt;b&gt;&lt;i&gt;&amp;lt;v,w&amp;gt;&lt;/i&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-path-to-node=&quot;5&quot; data-ke-size=&quot;size26&quot;&gt;개념2 - 벡터의 투영(Projection)과 수식 이해하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선형대수학에서 두 벡터의 관계를 다룰 때 &lt;b&gt;투영(Projection)&lt;/b&gt;은 필수적으로 등장하는 개념이다. &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;수식만 보면 복잡해 보이지만, 핵심은 아주 간단합니다. 바로 &lt;b&gt;그림자&lt;/b&gt;를 구하는 과정이다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Projection이 무엇인가?&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;712&quot; data-origin-height=&quot;574&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x9fZ0/dJMcaco1pOH/4Jv4cUKkIePSpPHki9C431/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x9fZ0/dJMcaco1pOH/4Jv4cUKkIePSpPHki9C431/img.png&quot; data-alt=&quot;ㄱ&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x9fZ0/dJMcaco1pOH/4Jv4cUKkIePSpPHki9C431/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx9fZ0%2FdJMcaco1pOH%2F4Jv4cUKkIePSpPHki9C431%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;337&quot; height=&quot;272&quot; data-origin-width=&quot;712&quot; data-origin-height=&quot;574&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ㄱ&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 벡터 &lt;b data-index-in-node=&quot;6&quot; data-path-to-node=&quot;7&quot;&gt;v&lt;/b&gt;가 있고, 그 아래에 기준이 되는 다른 벡터 &lt;b data-index-in-node=&quot;32&quot; data-path-to-node=&quot;7&quot;&gt;w&lt;/b&gt;가 있다고 가정해 보자. &lt;b data-index-in-node=&quot;50&quot; data-path-to-node=&quot;7&quot;&gt;w&lt;/b&gt; 벡터와 수직인 방향에서 빛을 비춘다면, 벡터 &lt;b data-index-in-node=&quot;77&quot; data-path-to-node=&quot;7&quot;&gt;v&lt;/b&gt;는 &lt;b data-index-in-node=&quot;80&quot; data-path-to-node=&quot;7&quot;&gt;w&lt;/b&gt; 위에 그림자가 생기게 된다. 이 그림자에 해당하는 새로운 벡터를 구하는 것이 바로 Projection(투영)이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;투영된 새로운 벡터를 구하려면 &lt;b&gt;크기(Magnitude)&lt;/b&gt;와 &lt;b data-index-in-node=&quot;38&quot; data-path-to-node=&quot;8&quot;&gt;방향(Direction)&lt;/b&gt; 두 가지 정보가 필요하다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size23&quot;&gt;2. 그림자의 '크기' 구하기&lt;/h3&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;삼각함수의 기본 원리에 의해, 빗변이 &lt;b data-index-in-node=&quot;21&quot; data-path-to-node=&quot;10&quot;&gt;v&lt;/b&gt;이고 밑변이 그림자인 직각삼각형을 떠올려 볼 수 있습니다. 두 벡터 사이의 각도를 &lt;span data-index-in-node=&quot;68&quot; data-math=&quot;\theta&quot;&gt;$\theta$&lt;/span&gt;라고 할 때, 그림자의 길이는 다음과 같이 구해집니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,0,0&quot;&gt;그림자의 크기 (Scalar):&lt;/b&gt; ||&lt;b data-index-in-node=&quot;11&quot; data-path-to-node=&quot;7,0,0&quot;&gt;v&lt;/b&gt;|| cos(&amp;theta;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size23&quot;&gt;2. 그림자의 '방향' 구하기&lt;/h3&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;그림자는 기준이 되는 벡터 &lt;b data-index-in-node=&quot;15&quot; data-path-to-node=&quot;13&quot;&gt;w&lt;/b&gt; 위에 맺히므로, 방향은 &lt;b data-index-in-node=&quot;30&quot; data-path-to-node=&quot;13&quot;&gt;w&lt;/b&gt;와 완전히 동일하다. 하지만 우리는 순수하게 '방향'만을 나타내는 단위 벡터(길이가 1인 벡터)가 필요하다. 따라서 벡터 &lt;b data-index-in-node=&quot;101&quot; data-path-to-node=&quot;13&quot;&gt;w&lt;/b&gt;를 자신의 전체 길이로 나누어준다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-path-to-node=&quot;11&quot;&gt;
&lt;li&gt;&lt;b data-path-to-node=&quot;11,0,0&quot; data-index-in-node=&quot;0&quot;&gt;그림자의 방향 (Direction Vector):&lt;/b&gt;&lt;span&gt; &lt;b data-index-in-node=&quot;10&quot; data-path-to-node=&quot;9,0,0&quot;&gt;w&lt;/b&gt; / ||&lt;b data-index-in-node=&quot;16&quot; data-path-to-node=&quot;9,0,0&quot;&gt;w&lt;/b&gt;||&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-path-to-node=&quot;9&quot; data-ke-size=&quot;size23&quot;&gt;3. 수식 합치기 : 투영 벡터 완성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 구한 '크기'와 '방향'을 곱해주면(Scalar multiplication) 우리가 원하는 투영 벡터의 공식이 나온다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZPfLX/dJMcafTAA0R/PppKqdl3lmyI8YYMKVMLZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZPfLX/dJMcafTAA0R/PppKqdl3lmyI8YYMKVMLZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZPfLX/dJMcafTAA0R/PppKqdl3lmyI8YYMKVMLZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZPfLX%2FdJMcafTAA0R%2FPppKqdl3lmyI8YYMKVMLZK%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;300&quot; height=&quot;136&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;136&quot;/&gt;&lt;/span&gt;&lt;/figure&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;앞서 언급한 내적의 기본 공식을 활용하기 위해, 위 식의 분모와 분자에 똑같이 ||&lt;b data-index-in-node=&quot;83&quot; data-path-to-node=&quot;12&quot;&gt;w&lt;/b&gt;||를 곱해주어 내적 기호 &amp;lt;&lt;b data-index-in-node=&quot;100&quot; data-path-to-node=&quot;12&quot;&gt;v&lt;/b&gt;, &lt;b data-index-in-node=&quot;103&quot; data-path-to-node=&quot;12&quot;&gt;w&lt;/b&gt;&amp;gt; 로 치환합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;254&quot; data-origin-height=&quot;152&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/thDAc/dJMcaiisvRu/zjQKnNrU6w8bHjbSGmtQBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/thDAc/dJMcaiisvRu/zjQKnNrU6w8bHjbSGmtQBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/thDAc/dJMcaiisvRu/zjQKnNrU6w8bHjbSGmtQBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FthDAc%2FdJMcaiisvRu%2FzjQKnNrU6w8bHjbSGmtQBK%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;254&quot; height=&quot;152&quot; data-origin-width=&quot;254&quot; data-origin-height=&quot;152&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로, 벡터 자기 자신의 크기를 두 번 곱한 분모의 ||&lt;b data-index-in-node=&quot;34&quot; data-path-to-node=&quot;14&quot;&gt;w&lt;/b&gt;|| ||&lt;b data-index-in-node=&quot;40&quot; data-path-to-node=&quot;14&quot;&gt;w&lt;/b&gt;|| 는 자기 자신을 내적한 &amp;lt;&lt;b data-index-in-node=&quot;58&quot; data-path-to-node=&quot;14&quot;&gt;w&lt;/b&gt;, &lt;b data-index-in-node=&quot;61&quot; data-path-to-node=&quot;14&quot;&gt;w&lt;/b&gt;&amp;gt; 와 수학적으로 완전히 동일하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 최종적으로 가장 깔끔한 형태의 투영 벡터 공식이 완성된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;210&quot; data-origin-height=&quot;144&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5Jukc/dJMcagSuV9L/bRIDw7t3RvCv1tEUJHBAck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5Jukc/dJMcagSuV9L/bRIDw7t3RvCv1tEUJHBAck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5Jukc/dJMcagSuV9L/bRIDw7t3RvCv1tEUJHBAck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5Jukc%2FdJMcagSuV9L%2FbRIDw7t3RvCv1tEUJHBAck%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;244&quot; height=&quot;167&quot; data-origin-width=&quot;210&quot; data-origin-height=&quot;144&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 벡터의 투영 원리는 단순히 수학적인 계산을 넘어, 카메라 앵글과 피사체의 구도를 실시간으로 분석해 정확한 피드백을 제공하는 등 컴퓨터 비전 서비스의 핵심적인 기초가 된다.&lt;/p&gt;</description>
      <category>공부하기싫다</category>
      <category>선형대수학</category>
      <category>영상처리 및 비전</category>
      <category>컴퓨터비전</category>
      <author>ralmyon</author>
      <guid isPermaLink="true">https://ralmyon.tistory.com/1</guid>
      <comments>https://ralmyon.tistory.com/1#entry1comment</comments>
      <pubDate>Fri, 3 Apr 2026 22:36:41 +0900</pubDate>
    </item>
  </channel>
</rss>