作者:July | 日期:2011年3月12日 | 接上篇繼續核心函數實現
接續上文,逐一實現主函數調用的所有關鍵函數,這是本文核心部分。
CvMat* halfSizeImage(CvMat* im) {
unsigned int i, j;
int w = im->cols / 2;
int h = im->rows / 2;
CvMat* imnew = cvCreateMat(h, w, CV_32FC1);
#define Im(ROW,COL) ((float*)(im->data.fl + im->step/sizeof(float)*(ROW)))[(COL)]
#define Imnew(ROW,COL) ((float*)(imnew->data.fl + imnew->step/sizeof(float)*(ROW)))[(COL)]
for (j = 0; j < h; j++)
for (i = 0; i < w; i++)
Imnew(j,i) = Im(j*2, i*2);
return imnew;
}
CvMat* doubleSizeImage(CvMat* im) {
unsigned int i, j;
int w = im->cols * 2;
int h = im->rows * 2;
CvMat* imnew = cvCreateMat(h, w, CV_32FC1);
#define Im(ROW,COL) ((float*)(im->data.fl + im->step/sizeof(float)*(ROW)))[(COL)]
#define Imnew(ROW,COL) ((float*)(imnew->data.fl + imnew->step/sizeof(float)*(ROW)))[(COL)]
for (j = 0; j < h; j++)
for (i = 0; i < w; i++)
Imnew(j,i) = Im(j/2, i/2);
return imnew;
}
CvMat* doubleSizeImage2(CvMat* im) {
unsigned int i, j;
int w = im->cols * 2;
int h = im->rows * 2;
CvMat* imnew = cvCreateMat(h, w, CV_32FC1);
#define Im(ROW,COL) ((float*)(im->data.fl + im->step/sizeof(float)*(ROW)))[(COL)]
#define Imnew(ROW,COL) ((float*)(imnew->data.fl + imnew->step/sizeof(float)*(ROW)))[(COL)]
// 先填充所有像素
for (j = 0; j < h; j++)
for (i = 0; i < w; i++)
Imnew(j,i) = Im(j/2, i/2);
/* 插值像素:A B C
E F G
H I J
A,C,H,J為原始像素;B,E,G,I,F為插值像素 */
// 插值 B 和 I
for (j = 0; j < h; j += 2)
for (i = 1; i < w - 1; i += 2)
Imnew(j,i) = 0.5 * (Im(j/2, i/2) + Im(j/2, i/2+1));
// 插值 E 和 G
for (j = 1; j < h - 1; j += 2)
for (i = 0; i < w; i += 2)
Imnew(j,i) = 0.5 * (Im(j/2, i/2) + Im(j/2+1, i/2));
// 插值 F
for (j = 1; j < h - 1; j += 2)
for (i = 1; i < w - 1; i += 2)
Imnew(j,i) = 0.25 * (Im(j/2, i/2) + Im(j/2+1, i/2) +
Im(j/2, i/2+1) + Im(j/2+1, i/2+1));
return imnew;
}
float getPixelBI(CvMat* im, float col, float row) {
int irow = (int)row, icol = (int)col;
float rfrac = 1.0 - (row - irow);
float cfrac = 1.0 - (col - icol);
int width = im->cols, height = im->rows;
#define ImMat(ROW,COL) ((float*)(im->data.fl + im->step/sizeof(float)*(ROW)))[(COL)]
// 邊界檢查
if (irow < 0 || irow >= height || icol < 0 || icol >= width) return 0;
if (row > height - 1) row = height - 1;
if (col > width - 1) col = width - 1;
float row1 = 0, row2 = 0;
if (cfrac < 1)
row1 = cfrac * ImMat(irow, icol) + (1.0 - cfrac) * ImMat(irow, icol+1);
else
row1 = ImMat(irow, icol);
if (rfrac < 1) {
if (cfrac < 1)
row2 = cfrac * ImMat(irow+1, icol) + (1.0 - cfrac) * ImMat(irow+1, icol+1);
else
row2 = ImMat(irow+1, icol);
}
return rfrac * row1 + (1.0 - rfrac) * row2;
}
void normalizeMat(CvMat* mat) {
#define Mat(ROW,COL) ((float*)(mat->data.fl + mat->step/sizeof(float)*(ROW)))[(COL)]
float sum = 0;
for (unsigned int j = 0; j < mat->rows; j++)
for (unsigned int i = 0; i < mat->cols; i++)
sum += Mat(j,i);
for (unsigned int j = 0; j < mat->rows; j++)
for (unsigned int i = 0; i < mat->cols; i++)
Mat(j,i) /= sum;
}
void normalizeVec(float* vec, int dim) {
float sum = 0;
for (unsigned int i = 0; i < dim; i++) sum += vec[i];
for (unsigned int i = 0; i < dim; i++) vec[i] /= sum;
}
float GetVecNorm(float* vec, int dim) {
float sum = 0.0;
for (unsigned int i = 0; i < dim; i++) sum += vec[i] * vec[i];
return sqrt(sum);
}
float* GaussianKernel1D(float sigma, int dim) {
unsigned int i;
float* kern = (float*)malloc(dim * sizeof(float));
float s2 = sigma * sigma;
int c = dim / 2;
float m = 1.0 / (sqrt(2.0 * CV_PI) * sigma);
double v;
for (i = 0; i < (dim + 1) / 2; i++) {
v = m * exp(-(1.0 * i * i) / (2.0 * s2));
kern[c+i] = v;
kern[c-i] = v;
}
// normalizeVec(kern, dim); // 可選歸一化
return kern;
}
CvMat* GaussianKernel2D(float sigma) {
int dim = (int)max(3.0f, 2.0 * GAUSSKERN * sigma + 1.0f);
if (dim % 2 == 0) dim++; // 確保為奇數
CvMat* mat = cvCreateMat(dim, dim, CV_32FC1);
#define Mat(ROW,COL) ((float*)(mat->data.fl + mat->step/sizeof(float)*(ROW)))[(COL)]
float s2 = sigma * sigma;
int c = dim / 2;
float m = 1.0 / (sqrt(2.0 * CV_PI) * sigma);
for (int i = 0; i < (dim + 1) / 2; i++) {
for (int j = 0; j < (dim + 1) / 2; j++) {
float v = m * exp(-(1.0*i*i + 1.0*j*j) / (2.0 * s2));
Mat(c+i, c+j) = v;
Mat(c-i, c+j) = v;
Mat(c+i, c-j) = v;
Mat(c-i, c-j) = v;
}
}
// normalizeMat(mat); // 可選歸一化
return mat;
}
float ConvolveLocWidth(float* kernel, int dim, CvMat* src, int x, int y) {
#define Src(ROW,COL) ((float*)(src->data.fl + src->step/sizeof(float)*(ROW)))[(COL)]
unsigned int i;
float pixel = 0;
int col, cen = dim / 2;
for (i = 0; i < dim; i++) {
col = x + (i - cen);
if (col >= 0 && col < src->cols)
pixel += kernel[i] * Src(y, col);
}
return pixel;
}
本文詳細實現了SIFT算法所需的核心基礎函數:圖像縮放、插值、歸一化、高斯核生成與卷積運算。下一步將構建完整的尺度空間、DoG金字塔、關鍵點檢測與特徵描述子生成流程。完整代碼結構清晰,無第三方庫依賴,適合深入理解SIFT算法內部機制。