2023. 5. 16. 15:46ㆍComputer/영상처리
보간법
순방향 매핑의 문제점(빈 공간 발생)을 해결하기 위하여 일반적으로 크기 변환을 구현할 때에는 역방향 매핑 방법을 사용한다. 역방향 매핑에서는 결과 영상의 각각의 픽셀에 대하여 대응되는 입력 영상의 픽셀 위치를 찾아 그 위치에서의 픽셀 값을 참조한다.
이처럼 영상의 기하학적 변환을 수행하는 경우에는 실수 좌표 상에서의 픽셀 값을 결정해야 하는 경우가 발생하며, 이때 주변 픽셀 값들을 이용하여 원하는 위치의 값을 추정하는 방법을 보간법(interpolation)이라고 한다.
크기변환과 회전변환에 보간법이 사용된다.
보간법1 - 최근방 이웃 보간법
가장 가까운 위치에 있는 픽셀의 값을 참조하는 방법 ex) (50.2, 32.8) -> (50, 33)
빠르고 구현하기 쉽지만 픽셀 값이 급격하게 변화하는 것 같은 계단 현상/블록 현상이 나타날 수 있다.
void IppResizeNearest(IppByteImage& imgSrc, IppByteImage& imgDst, int nw, int nh)
{
int w = imgSrc.GetWidth();
int h = imgSrc.GetHeight();
imgDst.CreateImage(nw, nh);
BYTE** pSrc = imgSrc.GetPixels2D();
BYTE** pDst = imgDst.GetPixels2D();
int i, j, x, y;
double rx, ry; // rx, ry는 입력 영상에서 참조할 픽셀 값의 실수 좌표
for (j = 0; j < nh; j++)
for (i = 0; i < nw; i++)
{
rx = static_cast<double>(w - 1) * i / (nw - 1);
ry = static_cast<double>(h - 1) * j / (nh - 1);
x = static_cast<int>(rx + 0.5);
y = static_cast<int>(ry + 0.5);
if (x >= w) x = w - 1;
if (y >= h) y = h - 1;
pDst[j][i] = pSrc[y][x];
}
}
보간법2 - 양방향 선형/양선형 보간법
양선형 보간법은 실수 좌표를 둘러싸고 있는 네 개의 픽셀 값에 가중치를 곱한 값들의 선형 합으로 결과 영상의 픽셀 값을 구한다.(3번 계산)
최근방 이웃 보간법에 비해서는 느린 편이지만, 비교적 빠른 편이고 계단 현상이 많이 감소한다.영상의 윤곽선이 많이 부드러워진다.
z = (1-p)(1-q)a + p(1-q)b + (1-p)qc + pqd
void IppResizeBilinear(IppByteImage& imgSrc, IppByteImage& imgDst, int nw, int nh)
{
int w = imgSrc.GetWidth();
int h = imgSrc.GetHeight();
imgDst.CreateImage(nw, nh);
BYTE** pSrc = imgSrc.GetPixels2D();
BYTE** pDst = imgDst.GetPixels2D();
int i, j, x1, y1, x2, y2;
double rx, ry, p, q, value;
for (j = 0; j < nh; j++)
for (i = 0; i < nw; i++)
{
rx = static_cast<double>(w - 1) * i / (nw - 1);
ry = static_cast<double>(h - 1) * j / (nh - 1);
// 정수형 변수 x1, x2, y1, y2는 각각 (rx, ry) 좌표를 둘러싼 4개의 픽셀 좌표
x1 = static_cast<int>(rx);
y1 = static_cast<int>(ry);
x2 = x1 + 1; if (x2 == w) x2 = w - 1;
y2 = y1 + 1; if (y2 == h) y2 = h - 1;
p = rx - x1;
q = ry - y1;
value = (1. - p) * (1. - q) * pSrc[y1][x1] //a
+ p * (1. - q) * pSrc[y1][x2] //b
+ (1. - p) * q * pSrc[y2][x1] //c
+ p * q * pSrc[y2][x2]; //d
pDst[j][i] = static_cast<BYTE>(limit(value + .5)); // value 값을 반올림하여 정수형으로 변환하고, 그 값을 결과 영상의 픽셀 값으로 저장
}
}
보간법3 - 3차 회선 보간법
고차 다항식을 이용한 보간법은 가중치 함수weight function를 정의하고, 원본 영상의 주변 픽셀 값에 가중치를 곱한 값을 모두 합하여 픽셀 값을 계산하는 방식을 사용한다. 각 행row에 대하여 보간을 먼저 실시한 후, 거기서 구해진 값들을 이용하여 다시 열column에 대한 보간을 수행하는 방식을 사용한다.
3차 회선 보간법은 둘러싸고 있는 16개의 픽셀 값에 3차 함수를 이용한 가중치를 부여한다. 총 5번의 보간이 이루어진다. 16개 점들을 각 행 단위로 나눠서 보간을 하여 그림의 삼각형 위치에서의 값을 추정한다. 그리고 4개의 삼각형 위치의 값을 이용하여 세로 방향으로 3차 회선 보간법을 수행하여 파란색 점 위치의 값을 추정하게 된다.
3차 함수를 이용하여 4개의 점에 대한 가중치를 계산하고, 픽셀의 값과 가중치를 곱한 값들의 합으로 결괏값을 계산한다. 이 가중치 함수가 3차 곡선의 모양을 가지기 때문에, 이 보간 방법을 3차 회선 보간이라고 부른다.
영상의 이동 변환
이동 변환된 결과 영상에서 원본 영상의 크기의 바깥으로 빠져나가는 픽셀들은 보이지 않게 될 것이고, 새로 생겨나는 빈 공간들은 그레이스케일 값 0으로 채워 넣을 것이다.
void IppTranslate(IppByteImage& imgSrc, IppByteImage& imgDst, int sx, int sy){
int w = imgSrc.GetWidth();
int h = imgSrc.GetHeight();
imgDst.CreateImage(w, h);
BYTE** pSrc = imgSrc.GetPixels2D();
BYTE** pDst = imgDst.GetPixels2D();
int i, j, x, y; // x와 y는 입력 영상의 픽셀 좌표
for(j=0; j<h; j++){ // i와 j는 결과 영상의 픽셀 좌표
for(i=0; i<w; i++){
x = i - sx;
y = j - sy;
if(x>=0 && y>=0 && x<w && y<h){ // 원본 영상에서 참조하는 픽셀 좌표가 영상의 크기를 벗어나지 않도록
pDst[j][i] = pSrc[y][x]; // 원본 영상 imgSrc의 픽셀 값을 참조하여 imgDst 영상의 픽셀 값을 설정
}
}
}
}
영상의 크기 변환
※ 영상의 축소 시 고려할 사항
◼ 한 픽셀로 구성된 선분들은 영상을 축소할 때 사라지는 경우가 발생
◼ 해결 방안 : 입력 영상을 부드럽게 필터링(스무)한 후 축소
영상의 회전 변환 - 시계방향 회전
회전 변환(rotation transform) – 시계방향 회전
영상을 특정 각도만큼 회전시키는 변환
영상을 원점 (0, 0)을 기준으로 세타 만큼 회전하는 경우,
- 특수 각도(90, 180, 270)에 대한 회전
90도 회전 x'=h-1-y, y'=x
180도 회전 x'=w-1-x, y'=h-1-y
270도 회전 x'=y, y'=w-1-x
void IppRotate90(IppByteImage& imgSrc, IppByteImage& imgDst)
{
int w = imgSrc.GetWidth();
int h = imgSrc.GetHeight();
imgDst.CreateImage(h, w);
BYTE** pSrc = imgSrc.GetPixels2D();
BYTE** pDst = imgDst.GetPixels2D();
int i, j;
for (j = 0; j < w; j++)
for (i = 0; i < h; i++)
{
pDst[j][i] = pSrc[h - 1 - i][j];
}
}
영상의 대칭 변환
대칭 변환1 - 좌우대칭
x'=w-1-x, y'=y
대칭 변환2 - 상하대칭
x'=x, y'=h-y-1
void IppFlip(IppByteImage& imgSrc, IppByteImage& imgDst)
{
int w = imgSrc.GetWidth();
int h = imgSrc.GetHeight();
imgDst.CreateImage(w, h);
BYTE** pSrc = imgSrc.GetPixels2D();
BYTE** pDst = imgDst.GetPixels2D();
int i, j;
for (j = 0; j < h; j++)
for (i = 0; i < w; i++)
{
pDst[j][i] = pSrc[h - 1 - j][i];
}
}
'Computer > 영상처리' 카테고리의 다른 글
영상의 특징값 추출 방법 (0) | 2023.05.25 |
---|---|
영상 새로 만들기 기능 구현(대화 상자 만들기) (0) | 2023.05.23 |
잡음 생성과 제거 (0) | 2023.05.09 |
Windows 프로그래밍과 Visual C++ (0) | 2023.03.24 |
영상 처리(image processing) (0) | 2023.03.24 |