2D Gaussian Convolution filter

2D space에서 image smoothing, noise 제거 등을 위해서 Gaussian filter를 적용할 때가 있다.

Matlab에는 워낙 다양한 toolbox들이 있어서 간혹 유사한 기능을 하는 함수들이 존재하기도 하는데, 때문에 같은 기능을 다양한 방식으로 구현을 할 수 있다.

오늘 imgaussfilt 함수와 mvnpdf 함수를 사용해서 Gaussian filter를 적용을 하다가 몇가지 차이점과 유의점을 발견하여 이곳에 적는다.

 

Original Image

코드 설명에 사용할 Original Image를 만드는 코드이다.

100 x 100 이미지에 (50, 50) 과 (20, 50) 의 pixel만 1의 값이 들어가있다.

originalImage = zeros(100,100);
originalImage(50, 50) = 1;
originalImage(20, 50) = 1;

Method 1: imgaussfilt

함수 개발 목적 자체가 2D 이미지에 Gaussian filter를 적용하기 위한 것이기 때문에 가장 간단하게 원하는 목적을 달성할 수 있다.

figure(1);
clf;
sigma = 1;
fimage1 = imgaussfilt(originalImage, sigma, 'FilterSize', 101);
imagesc(fimage1);

여기서 중요한 것은, 'FilterSize' Name-Value pair인데, 이 값을 입력하지 않거나, 작은 값으로 설정하는 경우 convolve 하는 kernel의 크기가 작아서 빠르지만 조금은 부정확한 결과가 나올 수 있다.

참고로 fimage1의 합은 2가 된다.

 

Method 2: mvnpdf로 kernel을 만든 뒤 conv2

직접 2D Gaussian kernel을 만든 뒤에 원본이미지와 conv2 함수를 사용해서 적용하는 방식이다.

[X,Y] = meshgrid(1:101, 1:101);
X = X(:);
Y = Y(:);
mu = 51;
sigma = [1, 0; 0, 1];
kernel = reshape(mvnpdf([X,Y],mu,sigma),101, 101);

fimage2 = conv2(originalImage, kernel, 'same');

figure(2);
imagesc(fimage2);

51의 값은 101 크기의 kernel의 중간값이다.

 

위 결과는 imgaussfilt의 결과와 정확히 일치한다.

 

 

 

함수 개발 목적 자체가 2D 이미지에 Gaussian filter를 적용하기 위한 것이기 때문에 가장 간단하게 원하는 목적을 달성할 수 있다.

Posted by Knowblesse

서론

Matlab이든 Python이든 image 처리를 할때 좌표축 때문에 머리가 아파오는 경우가 꼭 생긴다. 바로 일반적인 좌표계인 x,y 기준으로 위치를 잡을지, image도 array의 일종이니 row, col 기준으로 위치를 잡을지 생각해야 하는 시점이다. 사실 정말 단순한 문제인데 의외로 헷갈리고 각도라도 계산해야 하는 시점이 생기면 지옥이 펼쳐진다. 이 글은 매번 image 처리 파트를 할 때마다 좌표축을 헷갈리는 멍청한 본인을 한번에 이해시키기 위해서 쓰는 글이다.

 

Rule #1

좌측 : 데이터 저장 형태, 중간과 우측 : 데이터 입출력 형태

Matlab, Python, opencv, 캡쳐 프로그램, 지금까지 써본 모든 이미지 관련 프로그램들은 전부 이미지를 세 가지 형태중 하나의 형태로 사용한다. 그 이외의 형태는 아직까지 한번도 본적이 없다. 정확하게 말하자면 데이터 자체는 좌측과 같이 가지고 있고(실제 메모리에서의 구조보다는 indexing 기준), 사용자와 interaction을 해야하는 경우, 즉 마우스로 클릭을 하거나, line을 plot 하거나, figure의 현재 위치를 알려주거나 하는 경우는 중간이나 우측의 형태로 표기한다.

 

좌표축이 헷갈리는 가장 큰 원인은 개인적으로 데이터 입출력 형태가 두 가지가 있기 때문이라고 생각한다. indexing은 좌측, 입출력은 무조건 중간과 우측 중 하나의 형태만 취하면 그나마 혼동의 여지가 없겠으나, 입출력 형태가 2개가 있어서 혼란이 시작된다. 게다가 중간의 형태는 좌측의 형태와 정확히 일치하고 두 좌표값만 서로 바꾼 형태라 자칫 잘못하면 indexing을 method 1 방식으로 하게 되거나, method 1 방식으로 선을 그어주어야 하는데 indexing 하듯이 값을 넣을 수 있다.

 

가능한 모든 상황에서 테스트 해보면서 언제 어떤 식으로 좌표축이 표시되는지 확인해서 아래 정리해보았다.

사용하는 좌표축 형태 정리

  Matlab R2020a Python 3.7.3
(matplotlib=3.1.0)
Indexing indexing indexing
Method 1 (reversed Y axis) imshow, imagesc imshow
figure, object position
Method 2 (normal axis) figure, object position
plot, scatter 등 일반적인 graphic
plot, scatter 등 일반적인 graphic
현재 Method를 따름 ginput, drawline ginput

Indexing

모든 경우에서 indexing을 하는 경우는 일반적인 array의 row, col 방식을 따르기에 가장 단순하다.

예를 들어 가장 최상단 좌측 픽셀을 검은색으로 만들고 싶으면 Matlab과 Python 각각 아래와 같이 입력하면 된다.

img(1,1,:) = 0 % Matlab
img[0,0,:] = 0 # Python

Position Input

Matlab과 Python 모두 axis 상에서 마우스로 위치를 찍는 경우는 직관적으로 현재 axis의 상태를 그대로 따라 값을 저장해준다. 예를들어 imshow로 그림을 그려둔 상태에서 ginput을 실행하면 reversed Y axis 상태로 값을 기록한다. 반대로 plot 함수로 일반적인 cartesian 좌표계 상태라면 ginput 함수는 normal axis 상태로 값을 기록한다. 그러나 둘다 x, y 기준이지 row,col 기준이 아님을 기억하자.

 

Object Position(중요)

같은 기능에 대해서 여기서 Matlab과 Python, 그리고 다른 프로그램의 행동이 나뉘는 것 같다.

Python은 FigureManager의 geometry 속성 조절을 통해 window의 위치를 조정할 때 여타 image 처리에 사용되는 axis와 똑같이 reversed Y axis의 Method 1번 방식을 사용하는 반면, Matlab의 경우 Method 2 방식으로 figure window 의 position을 설정할 때 좌측 하단 구석이 원점이 된다.

 

GUI 개발을 할 때도 똑같은 형식으로 작동을 하는데, Matlab의 appdesigner를 사용하거나 ui가 붙는 object(button 등)를 만드는 경우 좌측 하단이 원점이 되는 Method 2 방식을 쓴다. Python으로는 GUI 개발을 해보지 않아서 확실히는 모르나 급히 PyQt5 관련 문서를 찾아보니 좌측 상단이 원점이 되는 Method 1 방식을 쓰는 것으로 보아 두 프로그램 모두  window position을 표기하는 방식과 동일하게 가는 것 같다.

 

Matlab(좌측)과 Python(우측)에서 1,1 위치에 Button object를 만든 경우

결론

결론적으로 이미지 데이터 입/출력은 무조건 Method 1 방법, Position과 관련된 경우는 사용 언어에 따라 체크를 하고 넘어가는 식으로 규칙을 생각해두는 것이 좋다. 위치 데이터를 저장할 때는 나중에 저장한 위치를 다시 표시할 것을 대비해서 Method 1의 방법으로 저장하는 것이 가장 편하지만 저장한 위치로 image array를 자르거나 하는 복잡한 작업을 할 때 일이 더 복잡해질 수 있다. 본인은 그래서 무조건 데이터 저장은 row, col 기준으로 저장을 하고 필요한 경우에만 x,y로 입출력을 하려고 한다.

 

나중에 추가할 내용

flipud 한 뒤 set('YDir', 'normal')

Posted by Knowblesse