Changed binarization to use integral types. Improves thresholding speed by 2x

This commit is contained in:
Matt Hill
2015-03-16 22:18:19 -04:00
parent 39c4756ce7
commit a5bfbca1ae
2 changed files with 141 additions and 174 deletions

View File

@@ -43,207 +43,174 @@ namespace alpr
// glide a window across the image and // glide a window across the image and
// create two maps: mean and standard deviation. // create two maps: mean and standard deviation.
// ************************************************************* // *************************************************************
float calcLocalStats (Mat &im, Mat &map_m, Mat &map_s, int winx, int winy)
{
float m,s,max_s;
long sum, sum_sq;
uchar foo;
int wxh = winx/2;
int wyh = winy/2;
int x_firstth= wxh;
int y_lastth = im.rows-wyh-1;
int y_firstth= wyh;
float winarea = winx*winy;
max_s = 0; double calcLocalStats (Mat &im, Mat &map_m, Mat &map_s, int winx, int winy) {
for (int j = y_firstth ; j<=y_lastth; j++) Mat im_sum, im_sum_sq;
{ cv::integral(im,im_sum,im_sum_sq,CV_64F);
float* mapm_rowdata = map_m.ptr<float>(j);
float* maps_rowdata = map_s.ptr<float>(j);
// Calculate the initial window at the beginning of the line double m,s,max_s,sum,sum_sq;
sum = sum_sq = 0; int wxh = winx/2;
for (int wy=0 ; wy<winy; wy++) int wyh = winy/2;
{ int x_firstth= wxh;
uchar* imdatarow = im.ptr<uchar>(j-wyh+wy); int y_lastth = im.rows-wyh-1;
for (int wx=0 ; wx<winx; wx++) int y_firstth= wyh;
{ double winarea = winx*winy;
foo = imdatarow[wx];
sum += foo;
sum_sq += foo*foo;
}
}
m = ((float)sum) / winarea; max_s = 0;
s = sqrt ((((float)sum_sq) - ((float)(sum*sum))/winarea)/winarea); for (int j = y_firstth ; j<=y_lastth; j++){
if (s > max_s) sum = sum_sq = 0;
max_s = s;
mapm_rowdata[x_firstth] = m;
maps_rowdata[x_firstth] = s;
// Shift the window, add and remove new/old values to the histogram sum = im_sum.at<double>(j-wyh+winy,winx) - im_sum.at<double>(j-wyh,winx) - im_sum.at<double>(j-wyh+winy,0) + im_sum.at<double>(j-wyh,0);
for (int i=1 ; i <= im.cols-winx; i++) sum_sq = im_sum_sq.at<double>(j-wyh+winy,winx) - im_sum_sq.at<double>(j-wyh,winx) - im_sum_sq.at<double>(j-wyh+winy,0) + im_sum_sq.at<double>(j-wyh,0);
{
// Remove the left old column and add the right new column
for (int wy=0; wy<winy; ++wy)
{
foo = im.uget(i-1,j-wyh+wy);
sum -= foo;
sum_sq -= foo*foo;
foo = im.uget(i+winx-1,j-wyh+wy);
sum += foo;
sum_sq += foo*foo;
}
m = ((float)sum) / winarea;
s = sqrt ((((float)sum_sq) - ((float) (sum*sum))/winarea)/winarea);
if (s > max_s)
max_s = s;
mapm_rowdata[i+wxh] = m;
maps_rowdata[i+wxh] = s;
}
}
return max_s; m = sum / winarea;
s = sqrt ((sum_sq - m*sum)/winarea);
if (s > max_s) max_s = s;
map_m.fset(x_firstth, j, m);
map_s.fset(x_firstth, j, s);
// Shift the window, add and remove new/old values to the histogram
for (int i=1 ; i <= im.cols-winx; i++) {
// Remove the left old column and add the right new column
sum -= im_sum.at<double>(j-wyh+winy,i) - im_sum.at<double>(j-wyh,i) - im_sum.at<double>(j-wyh+winy,i-1) + im_sum.at<double>(j-wyh,i-1);
sum += im_sum.at<double>(j-wyh+winy,i+winx) - im_sum.at<double>(j-wyh,i+winx) - im_sum.at<double>(j-wyh+winy,i+winx-1) + im_sum.at<double>(j-wyh,i+winx-1);
sum_sq -= im_sum_sq.at<double>(j-wyh+winy,i) - im_sum_sq.at<double>(j-wyh,i) - im_sum_sq.at<double>(j-wyh+winy,i-1) + im_sum_sq.at<double>(j-wyh,i-1);
sum_sq += im_sum_sq.at<double>(j-wyh+winy,i+winx) - im_sum_sq.at<double>(j-wyh,i+winx) - im_sum_sq.at<double>(j-wyh+winy,i+winx-1) + im_sum_sq.at<double>(j-wyh,i+winx-1);
m = sum / winarea;
s = sqrt ((sum_sq - m*sum)/winarea);
if (s > max_s) max_s = s;
map_m.fset(i+wxh, j, m);
map_s.fset(i+wxh, j, s);
}
}
return max_s;
} }
/********************************************************** /**********************************************************
* The binarization routine * The binarization routine
**********************************************************/ **********************************************************/
void NiblackSauvolaWolfJolion (Mat im, Mat output, NiblackVersion version, void NiblackSauvolaWolfJolion (Mat im, Mat output, NiblackVersion version,
int winx, int winy, float k) int winx, int winy, double k, double dR) {
{
float dR = BINARIZEWOLF_DEFAULTDR;
float m, s, max_s;
float th=0; double m, s, max_s;
double min_I, max_I; double th=0;
int wxh = winx/2; double min_I, max_I;
int wyh = winy/2; int wxh = winx/2;
int x_firstth= wxh; int wyh = winy/2;
int x_lastth = im.cols-wxh-1; int x_firstth= wxh;
int y_lastth = im.rows-wyh-1; int x_lastth = im.cols-wxh-1;
int y_firstth= wyh; int y_lastth = im.rows-wyh-1;
int y_firstth= wyh;
int mx, my;
// Create local statistics and store them in a float matrices // Create local statistics and store them in a double matrices
Mat map_m = Mat::zeros (im.rows, im.cols, CV_32F); Mat map_m = Mat::zeros (im.rows, im.cols, CV_32F);
Mat map_s = Mat::zeros (im.rows, im.cols, CV_32F); Mat map_s = Mat::zeros (im.rows, im.cols, CV_32F);
max_s = calcLocalStats (im, map_m, map_s, winx, winy); max_s = calcLocalStats (im, map_m, map_s, winx, winy);
minMaxLoc(im, &min_I, &max_I);
Mat thsurf (im.rows, im.cols, CV_32F);
// Create the threshold surface, including border processing
// ----------------------------------------------------
minMaxLoc(im, &min_I, &max_I); for (int j = y_firstth ; j<=y_lastth; j++) {
Mat thsurf (im.rows, im.cols, CV_32F); // NORMAL, NON-BORDER AREA IN THE MIDDLE OF THE WINDOW:
for (int i=0 ; i <= im.cols-winx; i++) {
// Create the threshold surface, including border processing m = map_m.fget(i+wxh, j);
// ---------------------------------------------------- s = map_s.fget(i+wxh, j);
for (int j = y_firstth ; j<=y_lastth; j++) // Calculate the threshold
{ switch (version) {
float* mapm_rowdata = map_m.ptr<float>(j);
float* maps_rowdata = map_s.ptr<float>(j);
float* thsurf_rowdata = thsurf.ptr<float>(j);
// NORMAL, NON-BORDER AREA IN THE MIDDLE OF THE WINDOW: case NIBLACK:
for (int i=0 ; i <= im.cols-winx; i++) th = m + k*s;
{ break;
m = mapm_rowdata[i+wxh];
s = maps_rowdata[i+wxh];
// Calculate the threshold case SAUVOLA:
switch (version) th = m * (1 + k*(s/dR-1));
{ break;
case NIBLACK:
th = m + k*s;
break;
case SAUVOLA: case WOLFJOLION:
th = m * (1 + k*(s/dR-1)); th = m + k * (s/max_s-1) * (m-min_I);
break; break;
default:
cerr << "Unknown threshold type in ImageThresholder::surfaceNiblackImproved()\n";
exit (1);
}
thsurf.fset(i+wxh,j,th);
case WOLFJOLION: if (i==0) {
th = m + k * (s/max_s-1) * (m-min_I); // LEFT BORDER
break; for (int i=0; i<=x_firstth; ++i)
thsurf.fset(i,j,th);
default: // LEFT-UPPER CORNER
cerr << "Unknown threshold type in ImageThresholder::surfaceNiblackImproved()\n"; if (j==y_firstth)
exit (1); for (int u=0; u<y_firstth; ++u)
} for (int i=0; i<=x_firstth; ++i)
thsurf.fset(i,u,th);
thsurf_rowdata[i+wxh] = th; // LEFT-LOWER CORNER
if (j==y_lastth)
for (int u=y_lastth+1; u<im.rows; ++u)
for (int i=0; i<=x_firstth; ++i)
thsurf.fset(i,u,th);
}
if (i==0) // UPPER BORDER
{ if (j==y_firstth)
// LEFT BORDER for (int u=0; u<y_firstth; ++u)
for (int i=0; i<=x_firstth; ++i) thsurf.fset(i+wxh,u,th);
thsurf_rowdata[i] = th;
// LEFT-UPPER CORNER // LOWER BORDER
if (j==y_firstth) if (j==y_lastth)
for (int u=0; u<y_firstth; ++u) for (int u=y_lastth+1; u<im.rows; ++u)
{ thsurf.fset(i+wxh,u,th);
float* thsurf_subrowdata = thsurf.ptr<float>(u); }
for (int i=0; i<=x_firstth; ++i)
thsurf_subrowdata[i] = th;
}
// LEFT-LOWER CORNER // RIGHT BORDER
if (j==y_lastth) for (int i=x_lastth; i<im.cols; ++i)
for (int u=y_lastth+1; u<im.rows; ++u) thsurf.fset(i,j,th);
{
float* thsurf_subrowdata = thsurf.ptr<float>(u);
for (int i=0; i<=x_firstth; ++i)
thsurf_subrowdata[i] = th;
}
}
// UPPER BORDER // RIGHT-UPPER CORNER
if (j==y_firstth) if (j==y_firstth)
for (int u=0; u<y_firstth; ++u) for (int u=0; u<y_firstth; ++u)
thsurf.fset(i+wxh,u,th); for (int i=x_lastth; i<im.cols; ++i)
thsurf.fset(i,u,th);
// LOWER BORDER // RIGHT-LOWER CORNER
if (j==y_lastth) if (j==y_lastth)
for (int u=y_lastth+1; u<im.rows; ++u) for (int u=y_lastth+1; u<im.rows; ++u)
thsurf.fset(i+wxh,u,th); for (int i=x_lastth; i<im.cols; ++i)
} thsurf.fset(i,u,th);
}
// RIGHT BORDER
for (int i=x_lastth; i<im.cols; ++i)
thsurf_rowdata[i] = th; for (int y=0; y<im.rows; ++y)
for (int x=0; x<im.cols; ++x)
// RIGHT-UPPER CORNER {
if (j==y_firstth) if (im.uget(x,y) >= thsurf.fget(x,y))
for (int u=0; u<y_firstth; ++u) {
{ output.uset(x,y,255);
float* thsurf_subrowdata = thsurf.ptr<float>(u); }
for (int i=x_lastth; i<im.cols; ++i) else
thsurf_subrowdata[i] = th; {
} output.uset(x,y,0);
}
// RIGHT-LOWER CORNER
if (j==y_lastth)
for (int u=y_lastth+1; u<im.rows; ++u)
{
float* thsurf_subrowdata = thsurf.ptr<float>(u);
for (int i=x_lastth; i<im.cols; ++i)
thsurf_subrowdata[i] = th;
}
}
for (int y=0; y<im.rows; ++y)
{
uchar* outputdatarow = output.ptr<uchar>(y);
uchar* imdatarow = im.ptr<uchar>(y);
float* thsurfdatarow = thsurf.ptr<float>(y);
for (int x=0; x<im.cols; ++x)
{
if (imdatarow[x] >= thsurfdatarow[x])
outputdatarow[x]=255;
else
outputdatarow[x]=0;
}
} }
} }
} }

View File

@@ -45,7 +45,7 @@ namespace alpr
#define fset(x,y,v) at<float>(y,x)=v; #define fset(x,y,v) at<float>(y,x)=v;
void NiblackSauvolaWolfJolion (cv::Mat im, cv::Mat output, NiblackVersion version, void NiblackSauvolaWolfJolion (cv::Mat im, cv::Mat output, NiblackVersion version,
int winx, int winy, float k); int winx, int winy, double k, double dR=BINARIZEWOLF_DEFAULTDR);
} }