"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "feats.cc" between
ocrad-0.24.tar.gz and ocrad-0.25.tar.gz

About: GNU Ocrad is an OCR (Optical Character Recognition) program.

feats.cc  (ocrad-0.24):feats.cc  (ocrad-0.25)
/* GNU Ocrad - Optical Character Recognition program /* GNU Ocrad - Optical Character Recognition program
Copyright (C) 2003-2014 Antonio Diaz Diaz. Copyright (C) 2003-2015 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or the Free Software Foundation, either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
skipping to change at line 40 skipping to change at line 40
#include "profile.h" #include "profile.h"
#include "feats.h" #include "feats.h"
Features::Features( const Blob & b_ ) Features::Features( const Blob & b_ )
: b( b_ ), hbar_initialized( false ), vbar_initialized( false ), : b( b_ ), hbar_initialized( false ), vbar_initialized( false ),
lp( b, Profile::left ), lp( b, Profile::left ),
tp( b, Profile::top ), rp( b, Profile::right ), bp( b, Profile::bottom ), tp( b, Profile::top ), rp( b, Profile::right ), bp( b, Profile::bottom ),
hp( b, Profile::height ), wp( b, Profile::width ) hp( b, Profile::height ), wp( b, Profile::width )
{} {}
void Features::row_scan_init() const
{
int l = -1; // begin of segment. -1 means no segment
row_scan.resize( b.height() );
for( int row = b.top(); row <= b.bottom(); ++row )
for( int col = b.left(); col <= b.right(); ++col )
{
bool black = b.get_bit( row, col );
if( l < 0 && black ) l = col; // begin of segment
if( l >= 0 && ( !black || col == b.right() ) ) // end of segment
{ row_scan[row-b.top()].push_back( Csegment( l, col - !black ) );
l = -1; }
}
}
void Features::col_scan_init() const
{
int t = -1; // begin of segment. -1 means no segment
col_scan.resize( b.width() );
for( int col = b.left(); col <= b.right(); ++col )
for( int row = b.top(); row <= b.bottom(); ++row )
{
bool black = b.get_bit( row, col );
if( t < 0 && black ) t = row; // begin of segment
if( t >= 0 && ( !black || row == b.bottom() ) ) // end of segment
{ col_scan[col-b.left()].push_back( Csegment( t, row - !black ) );
t = -1; }
}
}
int Features::hbars() const int Features::hbars() const
{ {
if( !hbar_initialized ) if( !hbar_initialized )
{ {
hbar_initialized = true; hbar_initialized = true;
const int limit = ( wp.max() + 1 ) / 2; if( row_scan.empty() ) row_scan_init();
int state = 0, begin = 0, l = 0, r = 0; std::vector< Csegment > segv;
std::vector< int > count( b.height(), 0 ); segv.reserve( b.height() );
for( int row = b.top(); row <= b.bottom(); ++row ) for( unsigned i = 0; i < row_scan.size(); ++i )
{ {
int col, c = 0, lt = 0, rt = 0, x = 0; if( row_scan[i].size() == 1 )
int & maxcount = count[row-b.top()]; { segv.push_back( row_scan[i][0] ); continue; }
for( col = b.left(); col <= b.right(); ++col ) int maxsize = 0, jmax = -1;
for( unsigned j = 0; j < row_scan[i].size(); ++j )
{ {
if( b.get_bit( row, col ) ) const int size = row_scan[i][j].size();
{ ++c; x = col; if( col < b.right() ) continue; } if( maxsize < size ) { maxsize = size; jmax = j; }
if( c > maxcount ) { maxcount = c; rt = x; lt = rt - c + 1; }
c = 0;
} }
if( jmax >= 0 ) segv.push_back( row_scan[i][jmax] );
else segv.push_back( Csegment() );
}
const int limit = ( wp.max() + 1 ) / 2;
int state = 0, begin = 0, l = 0, r = 0;
for( int i = 0; i < b.height(); ++i )
{
Csegment & seg = segv[i];
switch( state ) switch( state )
{ {
case 0: if( maxcount > limit ) case 0: if( seg.size() <= limit ) break;
{ state = 1; begin = row; l = lt; r = rt; } state = 1; begin = i; l = seg.left; r = seg.right;
else break; if( i < b.height() - 1 ) break;
case 1: if( maxcount > limit ) case 1: if( seg.size() > limit &&
( i <= begin || seg.overlaps( segv[i-1] ) ) )
{ {
if( lt < l ) l = lt; if( seg.left < l ) l = seg.left;
if( rt > r ) r = rt; if( seg.right > r ) r = seg.right;
if( row < b.bottom() ) break; if( i < b.height() - 1 ) break;
} }
state = 0; state = 0;
int end = ( maxcount <= limit ) ? row - 1 : row; int end = ( seg.size() <= limit ) ? i - 1 : i;
const int width = r - l + 1; const int width = r - l + 1;
while( begin <= end && 3 * count[begin-b.top()] < 2 * width ) while( begin <= end && 3 * segv[begin].size() < 2 * width )
++begin; ++begin;
while( begin <= end && 3 * count[end-b.top()] < 2 * width ) while( begin <= end && 3 * segv[end].size() < 2 * width )
--end; --end;
const int height = end - begin + 1; const int height = end - begin + 1;
if( height < 1 || 2 * height > 3 * width ) break; if( height < 1 || height > width ) break;
hbar_.push_back( Rectangle( l, begin, r, end ) ); const int margin = std::max( height, ( b.height() / 10 ) + 1 );
if( begin >= margin )
{
bool good = false;
for( int j = margin; j > 0; --j )
if( 3 * segv[begin-j].size() <= 2 * width )
{ good = true; break; }
if( !good ) break;
}
if( end + margin < b.height() )
{
bool good = false;
for( int j = margin; j > 0; --j )
if( 3 * segv[end+j].size() <= 2 * width )
{ good = true; break; }
if( !good ) break;
}
hbar_.push_back( Rectangle( l, begin+b.top(), r, end+b.top() ) )
;
break; break;
} }
} }
while( hbar_.size() > 3 ) // remove noise hbars while( hbar_.size() > 3 ) // remove noise hbars
{ {
int wmin = hbar_[0].width(); int wmin = hbar_[0].width();
for( unsigned i = 1; i < hbar_.size(); ++i ) for( unsigned i = 1; i < hbar_.size(); ++i )
if( hbar_[i].width() < wmin ) wmin = hbar_[i].width(); if( hbar_[i].width() < wmin ) wmin = hbar_[i].width();
for( int i = hbar_.size() - 1; i >= 0; --i ) for( int i = hbar_.size() - 1; i >= 0; --i )
if( hbar_[i].width() == wmin ) hbar_.erase( hbar_.begin() + i ); if( hbar_[i].width() == wmin ) hbar_.erase( hbar_.begin() + i );
skipping to change at line 144 skipping to change at line 202
int end = ( count * 3 < limit * 2 ) ? col - 1 : col; int end = ( count * 3 < limit * 2 ) ? col - 1 : col;
vbar_.push_back( Rectangle( begin, b.top(), end, b.bottom() ) ); vbar_.push_back( Rectangle( begin, b.top(), end, b.bottom() ) );
state = 0; state = 0;
} }
} }
} }
} }
return vbar_.size(); return vbar_.size();
} }
// return the number of vertical traces crossing every row Csegment Features::v_segment( const int row, const int col ) const
//
int Features::segments_in_row( const int row ) const
{
if( row_scan.empty() )
{
int l = -1; // begin of segment. -1 means no segment
row_scan.resize( b.height() );
for( int row = b.top(); row <= b.bottom(); ++row )
for( int col = b.left(); col <= b.right(); ++col )
{
bool black = b.get_bit( row, col );
if( l < 0 && black ) l = col; // begin of segment
if( l >= 0 && ( !black || col == b.right() ) ) // end of segment
{ row_scan[row-b.top()].push_back( Csegment( l, col - !black ) );
l = -1; }
}
}
return row_scan[row-b.top()].size();
}
// return the number of horizontal traces crossing every column
//
int Features::segments_in_col( const int col ) const
{
if( col_scan.empty() )
{
int t = -1; // begin of segment. -1 means no segment
col_scan.resize( b.width() );
for( int col = b.left(); col <= b.right(); ++col )
for( int row = b.top(); row <= b.bottom(); ++row )
{
bool black = b.get_bit( row, col );
if( t < 0 && black ) t = row; // begin of segment
if( t >= 0 && ( !black || row == b.bottom() ) ) // end of segment
{ col_scan[col-b.left()].push_back( Csegment( t, row - !black ) );
t = -1; }
}
}
return col_scan[col-b.left()].size();
}
// return the column segment containing the point (row,col) if any
//
Csegment Features::col_segment( const int row, const int col ) const
{ {
const int segments = segments_in_col( col ); const int segments = segments_in_col( col );
for( int i = 0; i < segments; ++i ) for( int i = 0; i < segments; ++i )
if( col_scan[col-b.left()][i].includes( row ) ) if( col_scan[col-b.left()][i].includes( row ) )
return col_scan[col-b.left()][i]; return col_scan[col-b.left()][i];
return Csegment(); return Csegment();
} }
int Features::test_misc( const Rectangle & charbox ) const int Features::test_misc( const Rectangle & charbox ) const
{ {
 End of changes. 14 change blocks. 
71 lines changed or deleted 84 lines changed or added

Home  |  About  |  All  |  Newest  |  Fossies Dox  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTPS