📄 common_gfx.h
字号:
/****************************************************************************** * 光学字符识别程序 * 文件名:commonv_gfx.h * 功能 :共用文件实现 * modified by PRTsinghua@hotmail.com******************************************************************************/#ifndef COMMON_GFX_H#define COMMON_GFX_H#include <math.h>#include <assert.h>#include <list>#include <vector>#include <qdialog.h>#include <qimage.h>#include "common_math.h"using std::list;using std::vector;// 点结构template<class T> struct point{ point( T init_x = 0, T init_y = 0 ) : x( init_x ), y( init_y ) {}; T x; T y; T get_x() const { return x; } T get_y() const { return y; } bool operator==(const point &p) const { return p.x == x && p.y == y; }};// 直线结构struct straight_line{ straight_line() : x( 0 ), y( 0 ), angle( 0 ) {} straight_line( float x1, float y1, float ang ) : x( x1 ), y( y1 ), angle( ang ) {} straight_line( float x1, float y1, float x2, float y2 ) : x( x1 ), y( y1 ), angle( atan2( y2 - y1, x2 - x1 ) ) {} float x; // 直线中心的x坐标 float y; // 直线中心的y坐标 float angle; // 直线的角度 float function( float xval ) const; bool intersect( const straight_line &line2, float &x_intersect, float &y_intersect ) const; // 两个直线的交点 straight_line normal( float x, float y ) const; void construct_perpendicular( float px, float py, float &x_perpendicular, float &y_perpendicular ) const;};// 线段结构class line_segment{public: line_segment() : p1( 0, 0 ), p2( 0, 0 ) {} line_segment( float x1, float y1, float x2, float y2 ) : p1( x1, y1 ), p2( x2, y2 ) {} line_segment( point<float> p1, point<float> p2 ) : p1( p1 ), p2( p2 ) {} float get_angle() { return atan2( p2.y - p1.y, p2.x - p1.x ); } bool intersect( const line_segment &seg2, bool touch_is_intersect = false, point<float> *pi = NULL ); private: point<float> p1; // 线段上的点1 point<float> p2; // 线段上的点2 float ang;};// T 必须拥有函数 get_x() 和 get_y()template<class T> struct correlation : public straight_line{ private: float cos_phi; // 脉冲的参数 float sin_phi; // 在线上添加新点 public: int num_points; // 序列中点的个数 typename list<T>::iterator first; // 序列的起点 typename list<T>::iterator last; // 序列终点 float sum_x; // x坐标和 float sum_y; // y坐标和 float mean_dist; // 点到相关直线的平均距离 correlation() : cos_phi(2), num_points(0), sum_x(0), sum_y(0), mean_dist(0) {} float distance(const T &p) const { return fabs((p.get_x()-x)*cos_phi+(p.get_y()-y)*sin_phi); } bool need_correlate() const { return cos_phi==2; } void set_need_correlate() { cos_phi=2; } void correlate(); void update();};template<class T> void correlation<T>::correlate(){ assert( num_points > 0 ); // 仅有一个点的线,认为是水平的 if( num_points == 1 ) { x = sum_x; y = sum_y; angle = 0; cos_phi = cos(angle+M_PI_2); sin_phi = sin(angle+M_PI_2); mean_dist = 0; return; } float x_average = sum_x / num_points; float y_average = sum_y / num_points; float sum_squares_x = 0; float sum_squares_y = 0; float sum_products = 0; #ifdef GRANT_CORRELATE_INTEGRITY float chk_sum_x = 0; float chk_sum_y = 0; float chk_num_points = 0; #endif typename list<T>::iterator i=first; do { #ifdef GRANT_CORRELATE_INTEGRITY chk_sum_x += i->get_x(); chk_sum_y += i->get_y(); chk_num_points++; #endif float deltax = i->get_x() - x_average; float deltay = i->get_y() - y_average; sum_squares_x += deltax * deltax; sum_squares_y += deltay * deltay; sum_products += deltax * deltay; } while( i++!=last ); #ifdef GRANT_CORRELATE_INTEGRITY assert( chk_sum_x == sum_x && chk_sum_y == sum_y && chk_num_points == num_points ); #endif float t = sum_squares_x - sum_squares_y; float u = ( sum_squares_x + sum_squares_y )/2.0; float v = sqrt( t*t + 4*sum_products*sum_products)/2.0; float lamda = u+v; // 矩阵A的特征值 // 计算特征向量 float x1=lamda - sum_squares_y, x2=lamda - sum_squares_x; if( fabs(x1)>fabs(x2) ) // 选择正确的方程计算特征向量 x2 = sum_products; else x1 = sum_products; // 保存结果 x = x_average; y = y_average; angle = normalize_line_angle( atan2(x2,x1) ); // 计算平均距离 cos_phi = cos(angle+M_PI_2); sin_phi = sin(angle+M_PI_2); mean_dist = 0; i = first; do { mean_dist += distance(*i); } while( i++ != last ); mean_dist /= num_points;}template<class T> void correlation<T>::update(){ sum_x = 0; sum_y = 0; num_points = 0; typename list<T>::iterator i = first; do { sum_x += i->get_x(); sum_y += i->get_y(); num_points++; } while( i++ != last ); correlate();}class Histogram : public QDialog{public: Histogram( QWidget *parent = 0, const char *name = 0 ); Histogram( const QImage &img, QWidget *parent = 0, const char *name = 0 ); void load( const QImage &img ); // 装载图像 void save(); // 保存直方图到文件 void print(); // 打印图像的统计信息 int get_bw_threshold() { return bw_threshold; } // 返回二值化的阈值 enum drawing_flags { draw_max_white = 0x00000001, draw_max_black = 0x00000002, draw_threshold = 0x00000004, draw_middle = 0x00000008, draw_mean_value = 0x00000010 }; private: void clear(); void toggle_draw_flag( unsigned int flag ); void drawHistogram( QPixmap &pixmap ); void paintEvent( QPaintEvent * ); void keyPressEvent( QKeyEvent *e ); unsigned long pix_count; // 图像中的点数 int min_value; // 图像中的最小灰度 int max_value; // 图像中的最大灰度 int mean_value; // 灰度均值 int most_value; // 最频繁出现的灰度值 int least_value; // 最少出现的灰度值 int std_deviation; // 标准分割 double entropy; // 图像熵 int white_maximum; // 直方图中白色最大值的位置 int black_maximum; // 直方图中黑色最大值的位置 int bw_threshold; // 分离阈值 unsigned int draw_flags; // 画图 vector<int> frequency; // 灰度频率 vector<float> log_frequency; // 灰度频率对数向量 QWidget *parent;};class AbstractImage{public: virtual int get_pixel( int /*x*/, int /*y*/ ) const { return 0; } virtual void set_pixel( int /*x*/, int /*y*/, int /*color*/ ) { } virtual bool is_background( int /*x*/, int /*y*/ ) const { return false; } virtual bool is_border_pixel( int x, int y ) const; virtual bool is_near_pixel( int x, int y ) const; };class CharImage: public AbstractImage, public QImage{public: // 缺省颜色 enum default_colors { black = 0, white = 255, transparent = 0, opaque = 255, bw_thresh = 127 }; CharImage( int threshold = bw_thresh ) : QImage(), bw_threshold( threshold ) {} CharImage( const QImage &img, int threshold = bw_thresh ) : QImage( img ), bw_threshold( threshold ) {} CharImage( int width, int height, int depth, int threshold = bw_thresh, int numColors = 0, Endian bitOrder = IgnoreEndian ) : QImage( width, height, depth, numColors, bitOrder ), bw_threshold( threshold ) {} virtual ~CharImage() { } virtual int get_pixel( int x, int y ) const; virtual void set_pixel( int x, int y, int col, int transparency = opaque ) { setPixel( x, y, qRgba( col, col, col, transparency ) ); } virtual bool is_background( int x, int y ) const { return is_background( x, y, bw_threshold ); } void fill( int color, int transparency = opaque ); void clear() { fill( white ); } void set_bw_threshold( int threshold = -1 ); int get_bw_threshold() { return bw_threshold; } bool get_bw_pixel( int x, int y, int threshold = -1 ) const; bool is_background( int x, int y, int threshold ) const { return !get_bw_pixel( x, y, threshold ); } bool is_background( int color ) const { return color > bw_threshold; } CharImage convert_bw( bool auto_threshold = false ) const; // 使用 bw_threshold 的特定转换函数 private: int bw_threshold; // 二值化阈值};inline int CharImage::get_pixel( int x, int y ) const{ if( x < 0 || x >= width() || y < 0 || y >= height() ) return white; else return qGray( pixel( x, y ) );}inline void CharImage::set_bw_threshold( int threshold ){ if ( threshold < 0 ) // 自动检测阈值 threshold = Histogram( *this ).get_bw_threshold(); bw_threshold = threshold;}inline bool CharImage::get_bw_pixel( int x, int y, int threshold ) const{ if ( threshold < 0 ) // 使用保存的阈值 return ( get_pixel( x, y ) <= bw_threshold ); return ( get_pixel( x, y ) <= threshold );}inline void CharImage::fill( int color, int transparency ){ for ( int y = 0; y < height(); y++ ) for ( int x = 0; x < width(); x++ ) set_pixel( x, y, color, transparency );}enum direction { down, right, up, left};inline direction operator++( direction &d ){ if( d == left ) return ( d = down); else return ( d = static_cast<direction> ( static_cast<int>( d ) + 1 ) );}inline direction operator--( direction &d ){ if( d == down ) return ( d = left ); else return ( d = static_cast<direction> ( static_cast<int>( d ) - 1 ) );}inline direction leftof( direction d ){ return ++d;}// 边缘跟踪class Walker{public: Walker() {}; void walk_border( int start_x, int start_y );protected: virtual bool is_border_pixel( int x, int y ) const = 0; virtual bool is_good_walker_start( int x, int y ) const = 0; virtual void walker_process( int /*x*/, int /*y*/ ) {}; virtual void walker_process2( int /*x*/, int /*y*/ ) {};};class CharImageWalker: public Walker{public: CharImageWalker( CharImage &image ) : img( image ) {} virtual ~CharImageWalker() {};private: virtual bool is_border_pixel( int x, int y ) const { return img.is_border_pixel( x, y ); } virtual bool is_good_walker_start( int x, int y ) const;protected: CharImage &img;};// 一些滤波器int filter( int x, int y, CharImage src, float H[3][3] );CharImage filter( CharImage src, float H[3][3] );CharImage filter( CharImage src, float Hx[3][3], float Hy[3][3], int mode );#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -