해당 포스트는 "열혈강의 영상처리 프로그래밍" 책의 내용을 요약한 것이다.
※ 입방 회선 보간
쌍선형 보간은 두 점 사이의 값을 1차 곡선인 직선을 통해 근사한 것이다. 입방 회선 보간에서는 x-1, x, x+1, x+2 네 개의 점을 이용하여 3차 곡선으로 근사한다. 입방 회선 보간도 쌍선형 보간과 마찬가지로 가로 세로 각 축에 대해서 계산한다. 각 위치의 픽셀 값을 I(x)로 표현한다면 I(x+p)는 입방 회선 보간의 3차 함수를 이용해 다음과 같이 구할 수 있다.
I(x+p) = {-I(x-1) + I(x) - I(x+1) + I(x+2)}*p^3 + {(2)I(x-1) - 2I(x) + I(x+1) + I(x+2)}p^2 + {-I(x-1) + I(x+1)}p + I(x)
위 다항식을 가로, 세로 축으로 각각 적용하면 x+p의 입방 회선 보간 결과를 얻을 수 있다. 아래는 x+p의 픽셀 값이 입방 회선 보간을 통해 얻어지는 코드이다.
BYTE CubicConvIntp(double x, double y) { int px[4], py[4]; //x-1,x,x+1,x+2 값을 구한다. px[0] = IN_IMG((int)x-1, 0, m_nWidth); px[1] = IN_IMG((int)x , 0, m_nWidth); px[2] = IN_IMG((int)x+1, 0, m_nWidth); px[3] = IN_IMG((int)x+2, 0, m_nWidth); //y-1, y, y+1, y+2 값을 구한다. py[0] = IN_IMG((int)y-1, 0, m_nHeight); py[1] = IN_IMG((int)y , 0, m_nHeight); py[2] = IN_IMG((int)y+1, 0, m_nHeight); py[3] = IN_IMG((int)y+2, 0, m_nHeight); // 위 다항식에서 대입할 p, p^2, p^3을 미리 계산한다. double dx = x - px[1]; double dy = y - py[1]; double dx2 = dx*dx; double dx3 = dx2*dx; double dy2 = dy*dy; double dy3 = dy2*dy; BYTE p0, p1, p2, p3; // 네 정수 좌표의 픽셀 값 double c1, c2, c3, c4; // 네 정수 좌표의 가중치 double C[4]; // 가로 방향 보간 결과 //가로 방향에 대해서 입방회선 보간을 한다. // 4개의 입방 회선 보간 결과를 구하는 이유는 // 세로 방향 y-1, y, y+1, y+2에 대해서 입방 회선 보간을 // 해야하기 때문이다. for (int i=0 ; i<4 ; i++) { p0 = m_pImageData[py[i]*m_nWStep + px[0]]; p1 = m_pImageData[py[i]*m_nWStep + px[1]]; p2 = m_pImageData[py[i]*m_nWStep + px[2]]; p3 = m_pImageData[py[i]*m_nWStep + px[3]]; c1 = p1; c2 = -p0 + p2; c3 = 2*(p0-p1) + p2 - p3; c4 = -p0 + p1 - p2 + p3; C[i] = c1 + c2*dx + c3*dx2 + c4*dx3; } //가로 회선 보간 결과 토대로 세로 방향으로 // 입방 회선 보간을 한다. c1 = C[1]; c2 = -C[0] + C[2]; c3 = 2*(C[0]-C[1]) + C[2] - C[3]; c4 = -C[0] + C[1] - C[2] + C[3]; return CLIP(c1 + c2*dy + c3*dy2 + c4*dy3); }
입방 회선 보간은 앞 포스트 쌍선형 보간에 비해 많은 계산이 필요하지만, 더욱 우수한 보간 결과를 보여준다.
※ 쌍입방 보간
쌍입방 보간은 16개의 정수 좌표 픽셀을 이용해 (x,y), (x+1,y), (x,y+1), (x+1, y+1) 영역을 곡면으로 보간하는 방법으로 각 영역을 미분해 곡면을 근사한다. 쌍선형 보간은 우리가 앞에서 4개의 점을 이용했다. 쌍입방 보간은 4개의 좌표를 미분해야 하기 때문에 쌍선형 보간에서 사용되는 4개의 점을 둘러쌓은 12개의 점을 추가로 이용한다.
쌍입방 보간 결과를 도출하는 다항식을 알기 위해서는 수학적 지식과 이해가 필요해 코드만 구현했다.
BYTE BiCubicIntp(double x, double y) { int x0 = IN_IMG((int)x-1, 0, m_nWidth); int x1 = IN_IMG((int)x , 0, m_nWidth); int x2 = IN_IMG((int)x+1, 0, m_nWidth); int x3 = IN_IMG((int)x+2, 0, m_nWidth); int y0 = IN_IMG((int)y-1, 0, m_nHeight); int y1 = IN_IMG((int)y , 0, m_nHeight); int y2 = IN_IMG((int)y+1, 0, m_nHeight); int y3 = IN_IMG((int)y+2, 0, m_nHeight); BYTE p00 = m_pImageData[y0*m_nWStep+x0]; BYTE p01 = m_pImageData[y1*m_nWStep+x0]; BYTE p02 = m_pImageData[y2*m_nWStep+x0]; BYTE p03 = m_pImageData[y3*m_nWStep+x0]; BYTE p10 = m_pImageData[y0*m_nWStep+x1]; BYTE p11 = m_pImageData[y1*m_nWStep+x1]; BYTE p12 = m_pImageData[y2*m_nWStep+x1]; BYTE p13 = m_pImageData[y3*m_nWStep+x1]; BYTE p20 = m_pImageData[y0*m_nWStep+x2]; BYTE p21 = m_pImageData[y1*m_nWStep+x2]; BYTE p22 = m_pImageData[y2*m_nWStep+x2]; BYTE p23 = m_pImageData[y3*m_nWStep+x2]; BYTE p30 = m_pImageData[y0*m_nWStep+x3]; BYTE p31 = m_pImageData[y1*m_nWStep+x3]; BYTE p32 = m_pImageData[y2*m_nWStep+x3]; BYTE p33 = m_pImageData[y3*m_nWStep+x3]; double f00 = p11; double f10 = p21; double f01 = p12; double f11 = p22; double fx00 = (p21-p01)/2.0; double fx10 = (p31-p11)/2.0; double fx01 = (p22-p02)/2.0; double fx11 = (p32-p12)/2.0; double fy00 = (p12-p10)/2.0; double fy10 = (p22-p20)/2.0; double fy01 = (p13-p11)/2.0; double fy11 = (p23-p21)/2.0; double fxy00 = (p22-p02-p20+p00)/4.0; double fxy10 = (p32-p12-p30+p10)/4.0; double fxy01 = (p23-p03-p21+p01)/4.0; double fxy11 = (p33-p13-p31+p11)/4.0; double a00 = f00; double a10 = fx00; double a20 = -3*f00 + 3*f10 -2*fx00 - fx10; double a30 = 2*f00 - 2*f10 + fx00 + fx10; double a01 = fy00; double a11 = fxy00; double a21 = -3*fy00 + 3*fy10 - 2*fxy00 - fxy10; double a31 = 2*fy00 - 2*fy10 + fxy00 + fxy10; double a02 = -3*f00 + 3*f01 - 2*fy00 - fy01; double a12 = -3*fx00 + 3*fx01 - 2*fxy00 - fxy01; double a22 = 9*f00 - 9*f10 - 9*f01 + 9*f11 + 6*fx00 + 3*fx10 - 6*fx01 - 3*fx11 + 6*fy00 - 6*fy10 + 3*fy01 - 3*fy11 + 4*fxy00 + 2*fxy10 + 2*fxy01 + fxy11; double a32 = -6*f00 + 6*f10 + 6*f01 - 6*f11 - 3*fx00 - 3*fx10 + 3*fx01 + 3*fx11 - 4*fy00 + 4*fy10 - 2*fy01 + 2*fy11 - 2*fxy00 - 2*fxy10 - fxy01 - fxy11; double a03 = 2*f00 - 2*f01 + fy00 + fy01; double a13 = 2*fx00 - 2*fx01 + fxy00 + fxy01; double a23 = -6*f00 + 6*f10 + 6*f01 - 6*f11 - 4*fx00 - 2*fx10 + 4*fx01 + 2*fx11 - 3*fy00 + 3*fy10 - 3*fy01 + 3*fy11 - 2*fxy00 - fxy10 - 2*fxy01 - fxy11; double a33 = 4*f00 - 4*f10 - 4*f01 + 4*f11 + 2*fx00 + 2*fx10 - 2*fx01 - 2*fx11 + 2*fy00 - 2*fy10 + 2*fy01 - 2*fy11 + fxy00 + fxy10 + fxy01 + fxy11; double dx = x - x1; double dx2 = dx*dx; double dx3 = dx2*dx; double dy = y - y1; double dy2 = dy*dy; double dy3 = dy2*dy; return CLIP( a00 + a01*dy + a02*dy2 + a03*dy3 + a10*dx + a11*dx*dy + a12*dx*dy2 + a13*dx*dy3 + a20*dx2 + a21*dx2*dy + a22*dx2*dy2 + a23*dx2*dy3 + a30*dx3 + a31*dx3*dy + a32*dx3*dy2 + a33*dx3*dy3); }
'영상처리 프로그래밍' 카테고리의 다른 글
영상의 기하학적 변환 (0) | 2017.06.12 |
---|---|
영상의 평행 이동, 회전, 확대 및 축소 (0) | 2017.06.12 |
픽셀 값의 보간 방법(2) - 쌍선형 보간 (0) | 2017.06.12 |
픽셀 값의 보간 방법(1) - 최단 입점 보간 (0) | 2017.06.12 |
영상의 광학적 변환(4) - 히스토그램 (0) | 2017.06.11 |
픽셀 값의 보간 방법(2) - 쌍선형 보간
해당 포스트는 "열혈강의 영상처리 프로그래밍" 책의 내용을 요약한 것이다.
※ 쌍선형 보간
쌍선형 보간은 값을 구하려는 픽셀 주변의 픽셀 값 4개의 변화양상을 추정하여 픽셀 값을 구하는 것이다. 먼저 쌍선형이 아닌 그냥 일차원 선형 보간의 원리를 아래 그림을 통해 살펴보자.
x는 정수 값을 가지는 픽셀 좌표에 해당하고 a와 b는 x, x+1 위치에서의 픽셀값을 나타낸다. p는 0에서 1사이의 소수점이다. c을 값을 구하기 위해 먼저 위 그래프에서 x를 0으로 가정하고 a-b 직선 함수 y = (b-a)x + a 를 만든다. 그리고 p를 대입한다. c는 (b-a)(p) + a가 되고 정리하면 (1-p)(a) + pb가 된다. 다음은 1차원 선형 보간을 2차원으로 확대해보자.
2차원 선형 보간은 1차원 선형보간을 두 번 수행하는거다. 구하고자 하는 좌표를 (x+p, y+p)라고 하자. 먼저 q에 대해서 (x,y)와 (x,y+1) , (x+1,y)와 (x+1,y+1) 사이의 1차원 보간을 구한다. (x,y)와 (x,y+1)사이의 1차원 보간을 e라고 하고 위에 1차원 보간을 구한 식에 대입해 보면 e= (1-q)(a) + qb가 된다. (x+1,y)와 (x+1,y+1) 사이의 1차원 보간을 f라고 하면 f = (1-q)c + qd가 된다. 마지막으로 e와 f 사이의 1차원을 구하면 된다. 이를 g라고 하면 g = (1-p)(e) + pf가 되고 여기에 우리가 구한 e와 f 값을 대입해 정리한다. 결과적으로 쌍선형 보간을 수행한 (x+p, y+q) 좌표의 픽셀 값은 g = (1-p)(1-q)(a) + (1-p)(q)(b) + p(1-q)(c) + (p)(q)(d) 가 된다. 이를 코드로 구현해보자.
BYTE BiLinearIntp(double x, double y) { double wLT, wRT, wLB, wRB; int xL = IN_IMG((int)x , 0, m_nWidth); int xR = IN_IMG((int)x+1, 0, m_nWidth); int yT = IN_IMG((int)y , 0, m_nHeight); int yB = IN_IMG((int)y+1, 0, m_nHeight); wLT = (xR - x)*(yB - y); wRT = (x - xL)*(yB - y); wLB = (xR - x)*(y - yT); wRB = (x - xL)*(y - yT); return (wLT*m_pImageData[yT*m_nWStep + xL] + wRT*m_pImageData[yT*m_nWStep + xR] + wLB*m_pImageData[yB*m_nWStep + xL] + wRB*m_pImageData[yB*m_nWStep + xR]); }
쌍선형 보간은 최단 입점 보간보다 더 졍교해지지만 영상이 약간 번진다. 다음에 살펴볼 입방 회전 보간이나 쌍입방 보간은 더욱 정교한 결과를 보여준다.
'영상처리 프로그래밍' 카테고리의 다른 글
영상의 평행 이동, 회전, 확대 및 축소 (0) | 2017.06.12 |
---|---|
픽셀 값의 보간 방법(3) - 입방 회선 보간 (0) | 2017.06.12 |
픽셀 값의 보간 방법(1) - 최단 입점 보간 (0) | 2017.06.12 |
영상의 광학적 변환(4) - 히스토그램 (0) | 2017.06.11 |
영상의 광학적 변환(3) - 영상 잡음 감소 (0) | 2017.06.10 |