학부 수업 내용 정리/전기전자심화설계및소프트웨어실습

#2 Image Resizing && Ratation

supersumin 2024. 9. 11. 19:15

이미지의 크기를 키워 저장하는 방법과 이미지를 회전시키는 방법에 알아보자. 그 전에 기본 연산에 대해 알아보자.

1. Basic Operations

- 파일 경로는 full path

Full path는 파일이 저장된 위치를 절대적으로 저장하므로 다른 파일 시스템에서든 같은 파일 시스템이든 해당 파일을 확실하게 찾을 수 있다. 이는 특히 여러 디렉토리가 존재하는 복잡한 프로젝트나 시스템에서 중요하다.

이 때 Windows 경로 포기인 백슬래시는 C언어에서 이스케이프 문자이므로 C언어에서 경로를 표시할 땐 두 번 써야한다.

 

- 이미지를 읽을 때 컬러로 처리할지 그레이스케일로 처리할지에 따라 사용하는 자료형이 달라진다.

  • 컬러 이미지(Vec3b)

컬러 이미지를 처리할 때는 보통 BGR (Blue, Green, Red) 형식으로 3개의 채널을 사용한다. OpenCV에서 컬러 이미지의 각 픽셀은 Vec3b 자료형으로 표현된다.

  • 그레이스케일 이미지(uchar)

그레이스케일 이미지는 각 픽셀이 단일 값을 가지며 밝기 정보만 포함하고 있다. 즉, 각 픽셀은 1채널을 가지며, uchar 자료형으로 처리된다.

 

- OpenCV에서의 이미지 초기화 방법

  • 그레이스케일 이미지 (1채널)

CV_8UC1은 1채널의 8비트 unsigned char 데이터를 의미한다. 각 픽셀은 0~255 범위의 값을 가지며 그레이스케일 이미지를 표현하는 데 사용한다.

  • 컬러 이미지 (3채널)

CV_8UC3은 3채널(BGR)의 8비트 unsigned char 데이터를 의미한다. 각 픽셀은 0~255 범위의 BGR (Blue, Green, Red) 값을 가지며 컬러이미지를 표현하는 데 사용된다.

  • 제로로 초기화된 이미지

Mat::zeros()는 모든 픽셀을 0으로 초기화된다. CV_32FC1은 1채널의 32비트 부동소수점(float) 형식이다. 각 픽셀은 0.0으로 초기화된다.

  • 원으로 초기화된 이미지

Mat::ones()는 모든 픽셀을 1로 초기화한다. CV_64FC3은 3채널(BGR)의 64비트 부동소수점(double) 형식이다. 각 채널의 픽셀 값은 1.0으로 초기화된다.

  • 특정 값으로 초기화된 이미지

이미지를 특정 값으로 초기화한다. CV_8UC1은 1채널 8비트 unsigned char 형식으로 각 픽셀은 0~255 범위의 값을 가진다. Scalar(39)는 모든 픽셀을 39로 초기화한다.

 

- Memory copy vs. address copy

데이터를 복사하는 방식에서 차이가 있다.

  • Memory Copy (메모리 복사)

메모리 복사는 실제 데이터를 완적히 복제하여 새로운 메모리 공간에 저장하는 방식이다. 원본 이미지와 복사된 이미지가 서로 독립적인 메모리 공간을 사용하게 되며 하나의 이미지를 수정해도 다른 이미지에는 영향을 미치지 않는다.

 

clone(): 원본 이미지를 완전히 복제하여 새로운 메모리 공간에 저장한다. 원본과 복사본은 독립적이다.

copyTo(): 이미 존재하는 이미지 객체에 데이터를 복사한다. 대상 이미지(img2)는 사전에 존재하고, 동일한 크기와 타입이어야 한다.

  • Address Copy (주소 복사)

주고 복사는 실제 데이터를 복사하지 않고 원본 데이터의 메모리 주소만 복사하는 방식이다. 복사된 객체는 원본 이미지의 참조를 공유하며 이 때문에 하나의 이미지를 수정하면 다른 이미지도 같이 변경된다.

 

이로 인해 copy와 original은 같은 메모리 공간을 공유한다.

 

- jpg, png, bmp 차이

  • JPG: 손실 압축을 사용하여 파일 크기를 줄이며, 일부 세부 정보가 손실될 수 있다. 파일 크기가 작고, 웹 및 사진 저장에 적합다.
  • PNG: 무손실 압축을 사용하여 원본 데이터를 완전히 유지한다. 파일 크기는 상대적으로 크며 투명도가 필요한 이미지와 고화질 이미지 저장에 적합합니다.
  • BMP: 무압축 포맷으로 이미지 데이터를 원본 그대로 저장한다. 파일 크기가 크며 데이터 손실 없이 품질을 완전히 유지하지만 저장 공간을 많이 차지한다.

 

2. 이미지 처리에서 특정 영역을 그레이스케일로 변환하는 방법

특정 영역을 흑백으로 만들기 위해서는 좌표를 중심으로 BLK만큼 그레이로 만들 것이다.(BLK: 한 블럭의 반지름)

 

좌표를 설정하기 전에 이미지의 가로, 세로 길이를 파악하고 좌표를 파악해야 한다. 그렇다면 이미지의 세로와 가로를 받아야 한다. 그리고 BLK 값을 받아 그레이로 그려야 한다.

 

 

3. OpenCV 기반 이미지 처리: 그레이스케일 변환과 Bi-linear 보간법을 통한 리사이징

- Bi-linear Interpolation(양선형 보간법)

이미지를 확대하거나 회전할 때, 새로운 픽셀 값을 예측하기 위해 사용되는 방법이다. 원본 이미지의 픽셀 위치가 정수로 떨어지지 않고 위치가 float 형식으로 표현된다. 이 경우 Bi-linear Interpolation이 사용된다.

 

Bi-linear 보간법에서 가중치 w가 곱해지게 된다. 그 이유는 픽셀의 상대적 위치에 따라 주변 4개의 픽셀 값을 결합하기 때문이다. 이는 내분점의 개념과는 조금 다르지만 비슷한 원리를 적용한다.

 

차이점은 내분점은 선 위에서 두 점 사이의 특정 위치 값을 계산하는 데 중점을 두는 반면, bi-linear 보간법은 2D 공간에서의 픽셀 사이 값들을 계산한다. 실제로 어떻게 이루어지는지 확인해보자.

내분점 공식을 통해 m의 값을 구할 수 있으며 m을 이와 같이 표현할 수 있다.

이제 각 점의 계수를 가중치로 표현하면 

이와 같이 표현할 수 있다.

 

* Bi-linear의 경우 내분점인데 분모에 나눠지는 값이 없는 이유 *

관심 픽셀의 주변에 있는 4개의 픽셀 값을 사용하여 가중치를 계산한 후 이를 평균내어 새로운 픽셀 값을 구하게 된다.

이 가중치는 해당 픽셀이 어느 위치에 있는지에 따라 결정되며 전체 가중치가 1이 되기 때문에 따로 나눗셈이 필요 없다.

 

예를 들어 dx + (1 - dx) = 1이고, 마찬가지로 dy + (1 - dy) = 1이기 때문에 가중치들이 자연스럽게 1로 합산된다. 그래서 추가적인 분모 처리가 필요하지 않은 것이다.

 

- Backward Filing

Backward Filling는 크기 조정, 회전 등 이미지 변환 시, 변환된 이미지의 각 픽셀 위치를 원본 이미지의 위치로 역으로 매핑하는 과정이다. 이 방법을 통해 변환된 이미지에서 각 픽셀의 값을 원본 이미지에서 추출할 수 있다.

 

- Code

output을 이미지를 생성한다. 그 이후 배열의 원소 값을 input에서 Bi-linear 연산을 통해 값을 가져온다. 또한 그 연산을 통해 output에 넣는 것 또한 것을 설정해줘야 한다.

 

 

4. OpenCV를 이용한 이미지 회전 및 보간 처리

이미지를 회전시키려면 어떻게 할까?

 

먼저 output을 담을 이미지를 생성한 뒤 원점을 중심으로 회전한 뒤 input 이미지에서 값을 가져와 보간하는 방법으로 생각해보자.

- Rotation Matrix (선형 변환의 중요한 성질)

2D에서의 회전 행렬은 다음과 같은 형태를 가진다.

이 행렬은 점이나 벡터를 원점 (0, 0)을 기준으로 시계 방향 또는 반시계 방향으로 회전시키는 데 사용된다. 여기서

회전 각도이다. 이 회전 행렬을 사용하면 특정 좌표 (x, y)로 회전시킬 수 있다.

 

아래는 반시계 방향, 시계 방향에 대해서 회전하는 예시를 보여준다.

 

- 원점을 이동한다고 해석할 수 있는 부분

원래 좌표계에서 이미지의 좌표는 좌상단으로 기준으로 한다. 하지만 좌표계를 이미지의 중심으로 이동시킨다면 회전이 중심을 기준으로 할 수 있다.

 

좌상단을 기준으로 하는 이유는 이중 for 문을 돌 때 x0, y0에 들어가는 값은 center_x와 center_y에 비례하게 된다. center_x와 center_y의 값이 0부터 시작된다면 이 주변의 값을 적게 회전하게 된다.

 

중앙값을 원하는 값을 음수로 넣어 코드에 넣는다면 원하는 좌표에서 회전할 수 있다.

 

 

* 2x2 행렬을 이용한 선형 변환 *

2x2 행렬이 나타내는 선형 변환의 경우 그 행렬의 각 열벡터가 기저 벡터 i와 j의 변환 결과를 나타낸다.

의 경우를 생각해보자. 

 

첫 번째 열 벡터

는 기저 벡터 i가 변환된 후의 좌표를 나타내고, 

 

두 번째 열 벡터 

는 기저 벡터 j가 변환된 후의 좌표를 나타낸다.

 

이를 통해 특정 벡터 

가 선형 변환에 의해 어디로 이동하는지 알고 싶다면 아래와 같이 계산할 수 있다.

 

- code