📄 common_gfx.cpp
字号:
/****************************************************************************** * 光学字符识别程序 * 文件名:common_gfx.cpp * 功能 :共用文件实现 * modified by PRTsinghua@hotmail.com******************************************************************************/#include <iostream>#include <qpainter.h>#include <qapplication.h>#include "common_gfx.h"using std::max;using std::cout;using std::endl;/****************************************************************************** * 判断是否边界点 * 参数:x x坐标 * y y坐标 * 返回:返回bool值******************************************************************************/bool AbstractImage::is_border_pixel( int x, int y ) const{ return !is_background( x, y ) && ( is_background( x-1, y ) || is_background( x+1, y ) || is_background( x, y-1 ) || is_background( x, y+1 ) ) ;}/****************************************************************************** * 判断是否邻接点 * 参数:x x坐标 * y y坐标 * 返回:返回bool值******************************************************************************/bool AbstractImage::is_near_pixel( int x, int y ) const{ if ( !is_background( x, y-1 ) || !is_background( x-1, y ) || !is_background( x+1, y ) || !is_background( x, y+1 ) ) return true; return false;}/****************************************************************************** * 二值化 * 参数:auto_threshold 是否自动检测阈值 * 返回:无******************************************************************************/CharImage CharImage::convert_bw( bool auto_threshold ) const{ int threshold = -1; if ( auto_threshold ) threshold = Histogram( *this ).get_bw_threshold(); CharImage img( width(), height(), 32 ); img.clear(); for( int y = 0; y < height(); y++ ) for( int x = 0; x < width(); x++ ) if ( !is_background( x, y, threshold ) ) img.set_pixel( x, y, black ); return img;}/****************************************************************************** * 构造函数******************************************************************************/Histogram::Histogram( QWidget *parent, const char *name ) : QDialog( parent, name ), parent( parent ){ setCaption("histogram"); clear(); }/****************************************************************************** * 构造函数******************************************************************************/Histogram::Histogram( const QImage &img, QWidget *parent, const char *name ) : QDialog( parent, name ), parent( parent ){ setCaption("histogram"); load( img );}/****************************************************************************** * 清空直方图******************************************************************************/void Histogram::clear(){ frequency = vector<int>( 256, 0 ); log_frequency = vector<float>( 256, 0 ); pix_count = 0; min_value = max_value = mean_value = 0; most_value = least_value = 0; std_deviation = 0; entropy = 0; white_maximum = black_maximum = 0; bw_threshold = 127; draw_flags = 0;}/****************************************************************************** * 加载图像******************************************************************************/void Histogram::load( const QImage &img ){ clear(); pix_count = img.width()*img.height(); min_value = INT_MAX; // 计算灰度值的频率 for( int y = 0; y < img.height(); y++ ) for( int x = 0; x < img.width(); x++ ) { int value = qGray( img.pixel( x, y ) ); min_value = min( min_value, value ); max_value = max( max_value, value ); mean_value += value; frequency[ value ]++; } if ( img.height()*img.width() > 0 ) mean_value = mean_value / pix_count; // 计算标准分割值 unsigned long dev_count = 0; for( int y = 0; y < img.height(); y++ ) for( int x = 0; x < img.width(); x++ ) { int value = qGray( img.pixel( x, y ) ); dev_count += ( value - mean_value ) * ( value - mean_value ); } if ( img.height()*img.width() > 1 ) std_deviation = qRound( sqrt( dev_count / ( pix_count - 1 ) ) ); int most = 0, least = INT_MAX; // 寻找最频繁和最少出现的灰度值 for( int value = min_value; value <= max_value; value++ ) { if ( frequency[ value ] > most ) { most = frequency[ value ]; most_value = value; } if ( frequency[ value ] < least ) { least = frequency[ value ]; least_value = value; } if ( frequency[ value ] != 0 ) { log_frequency[ value ] = log( frequency[ value ] ); float relative_frequency = frequency[ value ] / static_cast<float>( pix_count ); entropy += relative_frequency * log( relative_frequency ) / log( 2 ); } } entropy = - entropy; // 寻找局部最大的白色值 for( int value = min_value; value <= ( min_value + max_value ) / 2; value++ ) if ( frequency[ value ] != 0 && log_frequency[ white_maximum ] < log_frequency[ value ] ) white_maximum = value; // 寻找局部最大的黑色值 for( int value = ( min_value + max_value ) / 2; value <= max_value; value++ ) if ( frequency[ value ] != 0 && log_frequency[ black_maximum ] < log_frequency[ value ] ) // 避免假值 if ( log_frequency[ value-1 ] != 0 ) black_maximum = value; // 寻找最大值之间的最小值 bw_threshold = min( white_maximum, black_maximum ); int second_threshold = 0; for( int value = white_maximum+1; value < black_maximum; value++ ) { if ( frequency[ value ] > 0 && log_frequency[ bw_threshold ] > log_frequency[ value ] ) { bw_threshold = value; second_threshold = 0; } else if ( log_frequency[ bw_threshold ] == log_frequency[ value ] ) { second_threshold = value; } } if ( second_threshold != 0 ) bw_threshold = ( bw_threshold + second_threshold ) / 2; else if( bw_threshold == min( white_maximum, black_maximum ) ) { if ( white_maximum != black_maximum ) bw_threshold = ( white_maximum + black_maximum ) / 2; else bw_threshold = 127; } repaint();}/****************************************************************************** * 保存******************************************************************************/void Histogram::save(){ QPixmap pixmap( size().width(), size().height() ); drawHistogram( pixmap ); if ( !pixmap.save( "./histogram.png", "PNG" ) ) QApplication::beep();}/****************************************************************************** * 打印图像信息******************************************************************************/void Histogram::print(){ cout << "pixel count: " << pix_count << endl; cout << "minimum gray value: " << min_value << endl; cout << "maximum gray value: " << max_value << endl; cout << "mean gray value: " << mean_value << endl; cout << "standard deviation: " << std_deviation << endl; cout << "entropy: " << entropy<< endl; cout << "white minimum in histogram: " << white_maximum << endl; cout << "black minimum in histogram: " << black_maximum << endl; cout << "b/w threshold: " << bw_threshold << endl;}void Histogram::paintEvent( QPaintEvent * ){ QPixmap pixmap( size().width(), size().height() ); drawHistogram( pixmap ); // 画图 bitBlt( this, 0, 0, &pixmap );}/****************************************************************************** * 画直方图******************************************************************************/void Histogram::drawHistogram( QPixmap &pixmap ){ float x_scale = static_cast<float>( pixmap.width() ) / frequency.size(); float y_scale = static_cast<float>( pixmap.height() ) / log_frequency[ most_value ]; // 画背景 pixmap.fill( "white" ); QPainter painter( &pixmap ); painter.setPen( QPen( "black", static_cast<int>( ceil( x_scale ) ) ) ); for( int value = min_value; value <= max_value; value++ ) { painter.moveTo( qRound( value * x_scale ), size().height() ); painter.lineTo( qRound( value * x_scale ), qRound( ( log_frequency[ most_value ] - log_frequency[ value ] ) * y_scale ) ); if ( draw_flags != 0 ) { painter.save(); int x_position = qRound( value * x_scale ); if ( qRound( ( log_frequency[ most_value ] - log_frequency[ value ] ) * y_scale ) <= 0 ) painter.moveTo( qRound( value * x_scale ), size().height() ); // 画标注信息 if ( value == white_maximum && ( draw_flags & draw_max_white ) ) { painter.setPen( QPen( "blue", static_cast<int>( ceil( x_scale ) ) ) ); painter.lineTo( x_position, 0 ); } else if ( value == black_maximum && ( draw_flags & draw_max_black ) ) { painter.setPen( QPen( "blue", static_cast<int>( ceil( x_scale ) ) ) ); painter.lineTo( x_position, 0 ); } else if ( value == bw_threshold && ( draw_flags & draw_threshold ) ) { painter.setPen( QPen( "red", static_cast<int>( ceil( x_scale ) ) ) ); painter.lineTo( x_position, 0 ); } else if ( value == 127 && ( draw_flags & draw_middle ) ) { painter.setPen( QPen( "cyan", static_cast<int>( ceil( x_scale ) ) ) ); painter.lineTo( x_position, 0 ); } else if ( value == mean_value && ( draw_flags & draw_mean_value ) ) { painter.setPen( QPen( "green", static_cast<int>( ceil( x_scale ) ) ) ); painter.lineTo( x_position, 0 ); } painter.restore();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -