해당 포스트는 "OpenCV로 배우는 영상 처리 및 응용", "C++ API OpenCV 프로그래밍" 책의 내용을 요약한 것이다.
※ DFT 를 이용한 회선(convolution)
: f(x,y)와 g(x,y)의 회선은 각각의 푸리에 변환 F(u,v)와 G(u,v)의 곱셈을 수행한 결과를 역방향 푸리에 변환을 적용하여 계산한다.
※ DFT 를 이용한 상관관계(convolution)
: f(x,y)와 g(x,y)의 상관관계는 푸리에 변환 F(u,v)와 G(u,v)의 켤레 복소수의 곱셈을 역푸리에 변환을 하여 계산한다.
- Point2d phaseCorrelate(InputArray src1, InputArray src2, InputArray window, double* response=0)
: src1과 src2의 상관관계를 subpixel 수준으로 계산하고 즉, 픽셀 안 채널 수준으로 계산하고 상관관계가 최대값인 위치를 이용하여 영상의 중심으로부터의 위치를 반환한다. src1과 src2는 크기가 같아야 하며 CV_32FC1 또는 CV_64FC1 행렬이다. window는 경계 부분에서 에지를 약화시키기 위해 사용하는 윈도우이다. response는 상관관계 최대값 주변의 5*5 이웃값을 가지고 근사시킨 0과 1 사이의 상관계수 값이다. 이 함수는 최종적으로 역푸리에 변환을 수행하고 난 행렬을 저주파의 위치가 중심으로 가게 고주파의 위치가 바깥쪽으로 가도록 4개의 부분영역을 교환한다. 그리고 영상의 중심에 대한 상대 위치를 반환한다. 따라서 반환 값 즉, 상관관계가 최대값인 위치를 조정해줘야 한다. 글로는 이해하기 힘든데 다음의 예를 보면서 이해해보자.
#include "opencv2\opencv.hpp"
#include <iomanip>
using namespace cv;
using namespace std;
Point PhaseCorr(Mat &_A, Mat &_B, double *maxloc);
void Printmat(const char *strName, Mat m);
int main()
{
float dataA[] = { 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1,
1, 1, 9, 9, 1, 1,
1, 1, 9, 9, 1, 1,
1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1 };
float dataB1[] = { 9, 9, 1,
9, 9, 1,
1, 1, 1 };
Mat A(6, 6, CV_32F, dataA);
Mat B(3, 3, CV_32F, dataB1);
double phaseCorr;
Point peakLoc = PhaseCorr(A, B, &phaseCorr);
cout << "phaseCorr = " << phaseCorr << endl;
cout << "peakLoc = " << peakLoc << endl;
return 0;
}
Point PhaseCorr(Mat &_A, Mat &_B, double *maxValue)
{ // calculate convolution and correlation by DFT
int nW = getOptimalDFTSize(_A.cols + _B.cols - 1);
int nH = getOptimalDFTSize(_A.rows + _B.rows - 1);
Mat A;
copyMakeBorder(_A, A, 0, nH - (_A.rows), 0, nW - (_A.cols), BORDER_CONSTANT, 0);
Mat B;
copyMakeBorder(_B, B, 0, nH - (_B.rows), 0, nW - (_B.cols), BORDER_CONSTANT, 0);
// correlation: magF = IDFT(DFT(A)*conj(DFT(B)))
Mat dftA;
dft(A, dftA, DFT_COMPLEX_OUTPUT);
Mat dftB;
dft(B, dftB, DFT_COMPLEX_OUTPUT);
Mat dftD;
mulSpectrums(dftA, dftB, dftD, 0, true);// conjB = true
Mat matCmplx[2];
split(dftD, matCmplx);
// normalize by magnitude
Mat magF;
magnitude(matCmplx[0], matCmplx[1], magF);
divide(matCmplx[0], magF, matCmplx[0]);
divide(matCmplx[1], magF, matCmplx[1]);
merge(matCmplx, 2, dftD);
dft(dftD, magF, DFT_INVERSE | DFT_SCALE | DFT_REAL_OUTPUT);
// magF : phase correlation
Printmat("Corr=", magF);
Point peakLoc;
minMaxLoc(magF, NULL, maxValue, NULL, &peakLoc);
return peakLoc;
}
void Printmat(const char *strName, Mat m)
{
int x, y;
float fValue;
cout << endl << strName << endl;
cout << setiosflags(ios::fixed);
for (y = 0; y<m.rows; y++)
{
for (x = 0; x<m.cols; x++)
{
fValue = m.at<float>(y, x);
cout << setprecision(2) << setw(8) << fValue;
}
cout << endl;
}
cout << endl;
}위 코드는 phaseCorrelate를 사용하지 않고 직접 코딩해서 상관관계를 최대값을 구하는 프로그램이다. 위 결과 사진을 보면 실제로 [2,2]의 상관관계가 제일 높은 것을 알 수 있다. 다음은 phaseCorrelate 함수를 사용한 코드이다.
#include "opencv2\opencv.hpp" using namespace cv; using namespace std; int main() { Mat srcImage = imread("alphabet.bmp", IMREAD_GRAYSCALE); if (srcImage.empty()) return -1; String tName[] = { "A.bmp", "s.bmp", "b.bmp", "m.bmp" }; Mat dstImage; cvtColor(srcImage, dstImage, COLOR_GRAY2BGR); Mat src32f; srcImage.convertTo(src32f, CV_32F); for (int i = 0; i < 4; i++) { Mat tImage = imread(tName[i], IMREAD_GRAYSCALE); if (tImage.empty()) return -1; Mat tmpl32f; tImage.convertTo(tmpl32f, CV_32F); copyMakeBorder(tmpl32f, tmpl32f, 0, src32f.rows - tmpl32f.rows, 0, src32f.cols - tmpl32f.cols, BORDER_CONSTANT, 0); double phaseCorr; Point2d peakLoc = phaseCorrelate(src32f, tmpl32f, noArray(), &phaseCorr); Point2d center(src32f.cols / 2.0, src32f.rows / 2.0); /////////////////////////// // region1 // region2 // /////////////////////////// // region3 // region4 // /////////////////////////// peakLoc = (center - peakLoc); // phaseCorrelate 함수의 반환 포인트가 영상의
//중심을 기준으로 반환한다. peakLoc = center - t
// inverse of fftShift if (peakLoc.x < center.x) { if (peakLoc.y < center.y) // region 1 peakLoc += center; // to region 4 else // region 3 { peakLoc.x += center.x; // to region 2 peakLoc.y -= center.y; } } else { if (peakLoc.y < center.y) // region 2 { peakLoc.x -= center.x; // to region 3 peakLoc.y += center.y; } else // region 4 peakLoc -= center; // to region 1 } rectangle(dstImage, Point((int)peakLoc.x, (int)peakLoc.y), Point(peakLoc.x + tImage.cols, peakLoc.y + tImage.rows), Scalar(255, 0, 0), 2); } imshow("dstImage", dstImage); waitKey(); return 0; }
'OpenCV 프로그래밍' 카테고리의 다른 글
| kmeans, 코너점 검출 함수, 윤곽선 관련 특징 및 매칭 함수, 블록 껍질 (0) | 2017.06.28 |
|---|---|
| Canny,HoughLines, findContours, drawContours (0) | 2017.06.27 |
| dft, idft, mulSpectrums, 저주파/고주파 통과 필터 (0) | 2017.06.26 |
| getStructuringElement, erode, dilate, morphologyEx (0) | 2017.06.26 |
| getDerivKernels, Sobel, Scharr, Laplacian, LoG (0) | 2017.06.26 |