mirror of
https://github.com/kerberos-io/openalpr-base.git
synced 2025-10-21 02:49:24 +08:00
Changed binarization to use integral types. Improves thresholding speed by 2x
This commit is contained in:
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user