📄 page.cpp
字号:
lines.push_back( char_line() ); for ( int y = 0; y < scan.height(); y++ ) // 行数 { for ( int x = 0; x < scan.width(); x++ ) // 列数 { if ( scan.is_background( x, y ) ) // 搜索黑点 continue; list<char_line>::iterator line = lines.end(); for ( list<char_line>::iterator l = lines.begin(); l != lines.end(); ++l ) // 判断正确的行 { // 清空旧的已经识别行 if ( l->is_done() ) l->clear(); // 检验字符是否在另一行上 if ( line == lines.end() ) { if ( l->empty() ) line = l; else if ( l->same_line( x, y, true ) ) line = l; } } if ( line != lines.end() ) // 发现匹配行 { BoundingBox bb; extract_part( x, y, scan, bb ); // 构建包围盒 assert( bb.width() > 0 && bb.height() > 0 ); // 忽略变形 if ( ( ( bb.width() / bb.height() < very_long_character_ratio && bb.height() / bb.width() < very_long_character_ratio*1.5 ) ) && ( bb.area > bb.width()*bb.height() * min_area_divisor ) ) { last_x = x; line->add_char( bb ); // 添加字符到行 } } } // 行分割完成后,识别字符 if ( !lines.begin()->is_done() && ( !( --lines.end() )->same_line( last_x, y ) || y == scan.height()-1 ) ) { if ( y != scan.height()-1 ) { bool got_fooled = false; for ( list<char_line>::iterator l = lines.begin(); l != lines.end(); ++l ) if ( l->same_line( l->get_last_x(), y ) ) { got_fooled = true; break; } if ( got_fooled ) // 发现点所属于的行 continue; } repaint(); list<char_line>::iterator line1, line2; for( line1 = line2 = lines.begin(), ++line2; line1 != lines.end(); ++line1, ++line2 ) { if ( line1->empty() || line1->is_done() ) // 为空的情况 continue; else if ( ( line2 != lines.end() && !line2->empty() && line1->get_avg_height() < line2->get_avg_height()*base_line::diaresis_ratio ) || line1->intersects( *line2 ) ) { if ( !line2->merge_line( &( *line1 ) ) ) // 合并 { --line1; --line2; } continue; } base_line baseline( *line1 ); // 计算字符旋转后的最高高度 guarded_ptr<CharImage> part = line1->get_max_part()->part; float max_height = max_height_img.get_max_height( const_cast<const CharImage&>( *part ), -baseline.get_angle() ); collector.set_char_height( max_height ); // 计算行中的字符数目 for ( char_line::iterator mb = line1->begin(); mb != line1->end(); ++mb ) { QPixmap character( mb->width()+2, mb->height()+2 ); QPainter painter( &character ); painter.fillRect( 0, 0, mb->width()+2, mb->height()+2, QColor( "white" ) ); for ( list< BoundingBox >::iterator bb = mb->parts.begin(); bb != mb->parts.end(); ++bb ) { QPixmap part; assert( part.convertFromImage( *bb->part ) ); painter.drawPixmap( bb->min_x - mb->min_x, bb->min_y - mb->min_y, part ); } painter.end(); if ( char_count++ > 0 ) { int chosen = KMessageBox::warningYesNoCancel( NULL, "Continue to next character?" "\n" "Press 'Cancel' to cycle through all." ); if ( chosen == KMessageBox::No ) return; else if ( chosen == KMessageBox::Cancel ) char_count = INT_MIN; // 不再询问 } if ( !img ) return; CharImage char_img = character.convertToImage(); char_img.set_bw_threshold( hist->get_bw_threshold() ); if( data_base_def ) // 数据库定义模式 { abstract_character ac = img->vectorize( char_img, baseline.get_base_y( *mb ), max_height, -baseline.get_angle() ); if( *data_base_def ) char_db.append_char_def( ac, *( data_base_def++ ) ); } else // OCR 模式 { // 识别字符 recognized_char_group group = img->recognize( char_img, baseline.get_base_y( *mb ), max_height, -baseline.get_angle() ); group.set_geometrics( mb->min_x, mb->min_y, mb->width(), mb->height() ); collector.append_char( group ); } } if( !data_base_def ) // OCR 模式 collector.append_newline(); // 行结束的地方 if ( y < scan.height()-1 && ( line2 == lines.end() || line2->empty() ) && line1->get_next_line() ) y = line1->get_next_line(); if ( line2 == --lines.end() && !line2->empty() && line2->get_avg_height() < line1->get_avg_height()*base_line::diaresis_ratio ) { line1->clear(); ++line1, ++line2; lines.splice( lines.begin(), lines, line1 ); } else line1->set_done(); } // 缓冲区结尾 last_x = 0; } } if( !data_base_def ) // OCR 模式 collector.finish();}// 提取特征void Page::extract_part( int start_x, int start_y, CharImage &source, BoundingBox &bb ){ SizeWalker sizewalker( source, bb ); sizewalker.walk_border( start_x, start_y ); // 创建空图像 bb.part = guarded_ptr<CharImage>( new CharImage( bb.width(), bb.height(), 32, hist->get_bw_threshold() ) ); bb.part->setAlphaBuffer( true ); // 以一定透明度填充图像 bb.part->fill( CharImage::white, CharImage::transparent ); CopyWalker copywalker( source, bb ); copywalker.walk_border( start_x, start_y ); // 从字符部分到新图像移动像素 for ( int y = 0; y < bb.height(); y++ ) { int mode = 0; for ( int x = 0; x < bb.width(); x++ ) { int color = bb.part->get_pixel( x, y ); if ( color == CharImage::white && ( mode == 1 || mode == 3 ) ) mode--; // 搜索模式或拷贝模式 else if ( !bb.part->is_background( color ) ) { if ( mode == 1 || mode == 2 ) mode++; // 拷贝模式或监听模式 bb.area++; // 记住黑色像素的数目 source.set_pixel( x + bb.min_x, y + bb.min_y, CharImage::white ); // clear pixel from original image continue; } else if ( color < CharImage::white && bb.part->is_background( color ) ) { mode = 1; // 监听模式 continue; } if ( mode == 2 ) // 拷贝模式 { int scolor = source.get_pixel( x + bb.min_x, y + bb.min_y ); // 源像素颜色 bb.part->set_pixel( x, y, scolor ); // 拷贝像素 source.set_pixel( x + bb.min_x, y + bb.min_y, CharImage::white ); // 从源图像中清空像素 if ( !bb.part->is_background( scolor ) ) bb.area++; // 记住黑色像素的数目 } } } bb.min_x++; bb.min_y++; bb.max_x--; bb.max_y--;}// 设置缩放比率void Page::setScale( float scale ){ if ( scale > 0 ) { assure_range( 0, 3000/width(), scale ); int max_xpos = qRound( pix.width() * scale - width() ); int max_ypos = qRound( pix.height() * scale - height() ); assure_range( 0, max_xpos < 0 ? 0 : max_xpos, pix_xpos ); assure_range( 0, max_ypos < 0 ? 0 : max_ypos, pix_ypos ); } else pix_xpos = pix_ypos = 0; float min_scale = min( min( static_cast<float>( width() ) / ( pix.width() - pix_xpos ), static_cast<float>( height() ) / ( pix.height() - pix_ypos ) ), static_cast<float>( 1 ) ); pix_scale = scale < 0 ? scale : scale < min_scale ? min_scale : scale; repaint();}// 获取缩放比率float Page::getScale( bool realScale ) { float scale; if ( realScale ) switch ( static_cast<int>( pix_scale ) ) { case -1: scale = min( static_cast<float>( width() ) / ( pix.width() - pix_xpos ), static_cast<float>( height() ) / ( pix.height() - pix_ypos ) ); break; case -2: scale = static_cast<float>( width() ) / ( pix.width() - pix_xpos ); break; case -3: scale = static_cast<float>( height() ) / ( pix.height() - pix_ypos ); break; case -4: scale = 1; break; default: scale = pix_scale; } else scale = pix_scale; return scale; }// 设置 x 坐标void Page::setXPos( int xpos ){ if ( pix_scale != -1 && pix_scale != -2 ) { int max_xpos = qRound( pix.width() * getScale() - width() ); assure_range( 0, max_xpos < 0 ? 0 : max_xpos, xpos ); pix_xpos = xpos; repaint(); }}// 设置 y 坐标void Page::setYPos( int ypos ){ if ( pix_scale != -1 && pix_scale != -3 ) { int max_ypos = qRound( pix.height() * getScale() - height() ); assure_range( 0, max_ypos < 0 ? 0 : max_ypos, ypos ); pix_ypos = ypos; repaint(); }}// 画矩形void Page::drawRectangle( QPainter &p, float scale, int min_x, int min_y, int max_x, int max_y ){ p.drawRect( QRect( QPoint( qRound( min_x * scale - pix_xpos ), qRound( min_y * scale - pix_ypos ) ), QPoint( qRound( ++max_x * scale - pix_xpos ), qRound( ++max_y * scale - pix_ypos ) ) ) );}// 绘制事件void Page::paintEvent( QPaintEvent * ){ QPixmap pixmap( size() ); // 画背景 pixmap.fill( "grey" ); // 在pixmap上绘制信息 drawRecognitionState( pixmap, getScale(), pix_xpos, pix_ypos ); // 在窗口上实际绘制 bitBlt( this, 0, 0, &pixmap );}// 绘制识别状态void Page::drawRecognitionState( QPixmap &pixmap, float scale, int pix_xpos, int pix_ypos ){ QWMatrix m; m.scale( scale, scale ); QPixmap scaledPix; if ( draw_flags & draw_bw ) { if ( pix_bw.isNull() ) { CharImage img = pix.convertToImage(); img.set_bw_threshold( scan.get_bw_threshold() ); pix_bw.convertFromImage( img.convert_bw() ); } scaledPix = pix_bw.xForm( m ); } else scaledPix = pix.xForm( m ); int psize = max( 1, qRound( pen_size*scale ) ); QPen darkgreen( "darkgreen", psize, SolidLine, FlatCap, RoundJoin ); QPen red( "red", psize, SolidLine, FlatCap, RoundJoin ); QPen darkred( "darkred", psize, SolidLine, FlatCap, RoundJoin ); QPen darkmagenta( "darkmagenta", psize, SolidLine, FlatCap, RoundJoin ); QPen darkblue( "darkblue", psize, SolidLine, FlatCap, RoundJoin ); // 绘制图像 QPainter painter( &pixmap ); painter.drawPixmap( -pix_xpos, -pix_ypos, scaledPix ); // 绘制调试信息 for( list<char_line>::iterator line = lines.begin(); line != lines.end(); ++line ) { for ( char_line::iterator mb = line->begin(); mb != line->end(); ++mb ) { // 绘制包围盒 if( draw_flags & draw_boundingboxes ) { for ( list< BoundingBox >::iterator bb = mb->parts.begin(); bb != mb->parts.end(); ++bb ) { painter.setPen( darkblue ); drawRectangle( painter, scale, bb->min_x, bb->min_y, bb->max_x, bb->max_y ); } } // 绘制 metaboxes if( draw_flags & draw_metaboxes ) { int pos_shift = 0; if ( draw_flags & draw_boundingboxes ) // 避免重绘包围盒 pos_shift = 2 * pen_size; painter.setPen( darkgreen ); drawRectangle( painter, scale, mb->min_x - pos_shift, mb->min_y - pos_shift, mb->max_x + pos_shift, mb->max_y + pos_shift ); } // 绘制最高的字符 if( draw_flags & draw_maxpart ) { painter.setPen( darkmagenta ); const BoundingBox *mp = &( *line->get_max_part() ); drawRectangle( painter, scale, mp->min_x, mp->min_y, mp->max_x, mp->max_y ); } } if ( !line->empty() ) { base_line baseline( *line ); // 绘制基线 if ( draw_flags & draw_baseline ) { painter.setPen( red ); painter.moveTo( 0 - pix_xpos, qRound( baseline.get_line()->function( 0 ) * scale - pix_ypos ) ); painter.lineTo( qRound( pix.width() * scale - pix_xpos ), qRound( baseline.get_line()->function( pix.width() ) * scale - pix_ypos ) ); } if ( draw_flags & draw_basepoints ) { for ( list< point<float> >::iterator bp = baseline.begin(); bp != baseline.end(); ++bp ) { painter.save(); painter.setPen( darkred ); painter.setBrush( "darkred" ); painter.moveTo( qRound( bp->x * scale - pix_xpos ), qRound( bp->y * scale - pix_ypos ) ); int diameter = qRound( line->get_avg_height() / 10 * scale ); painter.drawEllipse( qRound( bp->x * scale - pix_xpos - diameter/2 ), qRound( bp->y * scale - pix_ypos - diameter/2 ), diameter, diameter ); painter.restore(); } } } }}// 改变线条粗细void Page::change_line_thickness( bool bigger ){ // 改变输出pixmap的线条粗细 if( bigger ) pen_size++; else { if( pen_size>1 ) pen_size--; else return; } repaint();}// 设置绘制标识void Page::set_draw_flag( drawing_flags flag, bool state ){ if( state ) draw_flags|=flag; else draw_flags&=~flag; repaint();}// 清空void Page::clear(){ pix_xpos = pix_ypos = 0; pix.resize( 0, 0 ); pix_bw.resize( 0, 0 ); lines.clear();}// 鼠标移动事件void Page::mouseMoveEvent( QMouseEvent *e ){ if( pix.width()!=0 ) { float scale = getScale(); int x = qRound( e->x() / scale ); int y = qRound( e->y() / scale ); app->slotStatusMsg( QString( "Position ( x, y ): %1, %2" ).arg( x ).arg( y ) ); }}// 创建快照void Page::makeSnapshot(){ float scale = getScale(); QPixmap pixmap( qRound( pix.width()*scale ), qRound( pix.height()*scale ) ); drawRecognitionState( pixmap, scale, 0, 0 ); if ( pixmap.save( "snapshot_page.png", "PNG" ) ) app->slotStatusMsg( "Snapshot of page saved..." ); else { QApplication::beep(); app->slotStatusMsg( "Snapshot of page could not be saved..." ); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -