Integral image를 사용해서 Mean과 Standard Deviation을 매번 계산하지 않도록 수정하면 속도를 대폭 향상시킬 수 있다. 이건 나중에 시간날 때 만들어보자~
more..
#define THRESH_BINARY 0
#define THRESH_GRAYSCALE 1
/* Sliding window size (Must be an odd number) */
#define KERNEL_SIZE 15
/* Maximum standard deviation for a grayscale document */
#define SAUVOLA_R_PARAM 128
/* Positive parameter to control the threshold */
#define SAUVOLA_K_PARAM 0.2
static double mean(IplImage *img, int row, int col, int border_size)
{
double total = 0.0;
int i, j;
CvScalar g;
for (i = row - border_size; i <= row + border_size; i++) {
for (j = col - border_size; j <= col + border_size; j++) {
g = cvGet2D(img, i, j);
total += (double) g.val[0];
}
}
return total / (KERNEL_SIZE * KERNEL_SIZE);
}
static double standard_deviation(IplImage *img, int row, int col,
int border_size, double m)
{
double total = 0.0;
double deviation;
int i, j;
CvScalar g;
for (i = row - border_size; i <= row + border_size; i++) {
for (j = col - border_size; j <= col + border_size; j++) {
g = cvGet2D(img, i, j);
deviation = (double) g.val[0] - m;
total += deviation * deviation;
}
}
return sqrt(total / (KERNEL_SIZE * KERNEL_SIZE));
}
/*
* @src and @dst images must have same size array
* @mode: THRESH_BINARY or THRESH_GRAYSCALE
*/
static int sauvola(const IplImage *src, IplImage *dst, int mode)
{
IplImage *temp = NULL;
int i, j, border_size;
border_size = floor(KERNEL_SIZE / 2.0);
temp = cvCreateImage(cvSize(src->width + border_size * 2,
src->height + border_size * 2),
src->depth, src->nChannels);
if (!temp)
return -1;
cvSetZero(temp);
cvCopyMakeBorder(src, temp, cvPoint(border_size, border_size),
IPL_BORDER_REPLICATE, cvScalarAll(0));
for (i = border_size; i < src->height + border_size; i++) {
for (j = border_size; j < src->width + border_size; j++) {
double m, s;
unsigned char t;
CvScalar g, b;
m = mean(temp, i, j, border_size);
s = standard_deviation(temp, i, j, border_size, m);
t = (unsigned char) (m * (1 + SAUVOLA_K_PARAM *
(s / SAUVOLA_R_PARAM - 1)));
g = cvGet2D(temp, i, j);
if (g.val[0] <= t) {
if (mode == THRESH_BINARY)
b.val[0] = 0;
else
b.val[0] = g.val[0];
} else {
b.val[0] = 255;
}
cvSet2D(dst, i - border_size, j - border_size, b);
}
}
cvReleaseImage(&temp);
return 0;
}

comments
comments rss (+댓글 쓰러가기)