#pragma once #include "OnLineCardSchemaStruct.h" #include "schema_struct.h" #include "identify_struct.h" namespace OnLineCard{ struct schema_const_param{ //试卷宽度(扫描后图片的大小(可以使用像素),越大越准确) int shijuanwidth; //试卷高度 int shijuanheight; //内容高度(考试文本最顶部内容到页码底部间距离) int contenth; //内容顶部缩进(第一个定位点上边框到考试文本内容最上边内容距离) int content_margin_top; //第一块最小高度(试卷最左上角的矩形框要求的最小高度) int first_content_min_height; //内容(左侧)检测x偏移量 int content_detect_left_offsetx; //内容(右侧)检测x偏移量 int content_detect_right_offsetx; //内容检测宽度 int content_detect_w; /************************************************************************/ /* 定位点相关常亮 */ /************************************************************************/ //上下左右4边定位点的最大最小宽高 double main_locate_point; //主定位点在4个不同方向的最小宽度 int minw[4]; //主定位点在4个不同方向的最大宽度 int maxw[4]; //主定位点在4个不同方向的最小高度 int minh[4]; //主定位点在4个不同方向的最大高度 int maxh[4]; //版本定位点检测区域相对第一个定位点的位置 的x坐标 int version_detect_offsetx; //版本定位点检测区域相对第一个定位点的位置 的y坐标 int version_detect_offsety; //版本定位点检测区域宽度 int version_detect_width; //版本定位点检测区域高度 int version_detect_height; //版本定位点在4个不同方向的最小宽度 int version_minw[4]; //版本定位点在4个不同方向的最大宽度 int version_maxw[4]; //版本定位点在4个不同方向的最小高度 int version_minh[4]; //版本定位点在4个不同方向的最大高度 int version_maxh[4]; //题目定位点的最大宽高 int left_offsetx; int right_offsetx; int qd_detect_w; int maxw2; int minw2; int maxh2; int minh2; /************************************************************************/ /* 试卷条码位置相关常量 */ /************************************************************************/ //试卷条码位置(相对第一个定位点位置,大概位置不到真正的二维码区域,可以理解是放大扫描空间的图片区域) int paper_bar_offsetx; int paper_bar_offsety; int paper_bar_width; int paper_bar_height; /************************************************************************/ /* 学生条码位置相关常量 */ /************************************************************************/ //试卷条码位置(相对第一个定位点位置,大概位置不到真正的二维码区域,可以理解是放大扫描空间的图片区域) int paper_bar_offsetx1; int paper_bar_offsety1; int paper_bar_width1; int paper_bar_height1; //缺考标记相关参数 int quekao_item_offset_x; int quekao_item_offset_y; int quekao_item_width; int quekao_item_height; //学号 #define stuid_max_question_count 14 int stuid_max_question_count2; int stuid_question_offset[stuid_max_question_count];//每题x轴偏移量 int stuid_tudian_w; //涂点宽度 int stuid_tudian_h; //涂点高度 int stuid_item_offset_y; //第一排涂点y轴偏移量 int stuid_item_offset_len; //每排Y轴偏移量,因为是表格,所以间隔固定 /************************************************************************/ /* 客观题相关常量 */ /************************************************************************/ //每一横排最大选择题数量(存储空间) #define xuanze_max_question_count 24 #define xuanze_max_item_count 4 //每一横排最大选择题数量 int xuanze_max_question_count2; int xuanze_question_offset[xuanze_max_question_count];//每题x轴偏移量 int xuanze_item_offset[xuanze_max_item_count];//每题涂点y轴偏移量 int xuanze_question_header_offsety;//题号的y坐标偏移 int tudian_w;//涂点宽度 int tudian_h;//涂点高度 int xuanze_item_offset_y; //第一排涂点y轴偏移量 int xuanze_item_offset_len; //每排Y轴偏移量,因为是表格,所以间隔固定 /************************************************************************/ /* 不定项选择相关常量(多选题) */ /************************************************************************/ //每一横排最大选择题数量(存储空间) #define xuanze_max_question_count3 24 #define xuanze_max_item_count3 10 //每一横排最大选择题数量 int xuanze_max_question_count4; int xuanze_question_offset3[xuanze_max_question_count3];//每题x轴偏移量 int xuanze_item_offset3[xuanze_max_item_count3];//每题涂点y轴偏移量 int xuanze_question_header_offsety3;//题号的y坐标偏移 int tudian_w3;//涂点宽度 int tudian_h3;//涂点高度 int xuanze_item_offset_y3; //第一排涂点y轴偏移量 int xuanze_item_offset_len3; //每排Y轴偏移量,因为是表格,所以间隔固定 /************************************************************************/ /* 填空题相关常量 (江苏卷) */ /************************************************************************/ //评分框宽度 int tikong_w; //评分框高度 int tikong_h; //每一横排最大填空题数量 #define tiangkong_max_question_count 2 //每题x轴偏移量(相对题目定位点的偏移) int tiangkong_question_offset[tiangkong_max_question_count]; //每题结束位置x轴偏移量 int tiangkong_end_offset[tiangkong_max_question_count]; //每题开始位置x轴偏移量 int tiangkong_start_offset[tiangkong_max_question_count]; //填空题评分框y偏移量 int tiankong_offsety; //填空题切割区域y偏移量(相对题目定位点的偏移) int tiankong_area_offsety; //填空题切割区域高度 int tiankong_area_height; //评分框宽度阀值(动态检查时用到) int tiankong_w2; //评分框宽度阀值误差范围 int tiankong_w3; //评分框高度阀值 int tiankong_h2; //评分框高度阀值误差范围 int tiankong_h3; #define tiankong_per_mode_type 5 //数组0:全国 1:江苏 2:浙江 3:大分数 //评分框宽度 int tikong_w_arr[tiankong_per_mode_type]; //评分框高度 int tikong_h_arr[tiankong_per_mode_type]; //每题x轴偏移量(相对题目定位点的偏移),自定义一行一个填空题 int tiangkong_question_offset_arr[tiankong_per_mode_type]; //每题结束位置x轴偏移量 int tiangkong_end_offset_arr[tiankong_per_mode_type]; //每题开始位置x轴偏移量 int tiangkong_start_offset_arr[tiankong_per_mode_type]; //填空题评分框y偏移量 int tiankong_offsety_arr[tiankong_per_mode_type]; //填空题切割区域y偏移量(相对题目定位点的偏移) int tiankong_area_offsety_arr[tiankong_per_mode_type]; //填空题切割区域高度 int tiankong_area_height_arr[tiankong_per_mode_type]; /************************************************************************/ /* 填空题相关常量 (全国卷) 选择题和填空题共用一个题目定位点 */ /************************************************************************/ int qtikong_w;//评分框宽度 int qtikong_h;//评分框高度 //每一横排最大填空题数量 #define qtiangkong_max_question_count 1 #define qtiangkong_max_pai_count 4 //每题x轴偏移量 int qtiangkong_question_offset[tiangkong_max_question_count]; //每题结束位置x轴偏移量 int qtiangkong_end_offset[tiangkong_max_question_count]; //每题开始位置x轴偏移量 int qtiangkong_start_offset[tiangkong_max_question_count]; //每题排y轴偏移量 int qtiangkong_pai_offset[qtiangkong_max_pai_count]; //填空题评分框y偏移量 int qtiankong_offsety; //填空题切割区域y偏移量 int qtiankong_area_offsety; //填空题切割区域高度 int qtiankong_area_height; //评分框宽度阀值 int qtiankong_w2; //评分框宽度阀值误差范围 int qtiankong_w3; //评分框高度阀值 int qtiankong_h2; //评分框高度阀值误差范围 int qtiankong_h3; /************************************************************************/ /* 主观题相关常量 */ /************************************************************************/ //每一横排评分框数量 #define zhuguanti_max_question_count 23 int zhuguanti_question_offset[zhuguanti_max_question_count];//每评分框x轴偏移量 int zhuguanti_w;//评分框宽度 int zhuguanti_h;//评分框高度 int zhuguanti_h2;//评分框高度阀值(评分数据框上下两边距离) int zhuguanti_h3;//评分框高度阀值误差范围(允许的上下两边实际误差范围) //主观题偏移位置 int zhuguanti_offsetx; int zhuguanti_offsety; int zhuguanti_item_count;//主观题总共格子数(目前23个) //主观题最后一个格子相对右边地位点的偏移量(右边第一个分数框到右边题目定位点距离) int zhuguanti_r_offsetx; int zhuguanti_r_offsety; //主管题格子的宽高 int zhuguanti_item_w; int zhuguanti_item_h; double main_locate_point_distance; //题目定位点距离 double question_locate_point_distance; int group_count; int group_question_count; /************************************************************************/ /* 附加题相关常量 */ /************************************************************************/ #define qxuanzuoti_max_count 4 int qxuanzuoti_question_offsetx[qxuanzuoti_max_count]; int qxuanzuoti_question_offsety[qxuanzuoti_max_count]; int qxuanzuoti_item_w; int qxuanzuoti_item_h; }; //分析结果 struct OnlineAnalyseResult{ //填涂项数量 int cellNum; //填涂项灰度平均值 int cellAvgGray; //全局背景灰度 int backGroundGray; //填涂项结果 struct itemResult{ //黑度 double heidu; //模糊度 double mohudu; //相对面积(黑点面积与总面积之比) double xiangdui_mianji; //相对值(有灰度与面积计算的一个参考值) double xiangdui_value; //填涂区域的平均灰度 int avg_gray; //相对背景被涂黑点数 int gray_num; //涂点大小 int cell_size; //字符区域大小 int char_area_size; //字符区域黑色点数(统计选项的字符区域的灰度判定为黑色的点数,用于统计试卷该选项全局的平均字符黑点数) int char_area_black_count; //字符区域黑色点的平均灰度 double char_area_avg_gray; }itemAnalyseResult[2048]; //平均黑度 double avg_heidu; //浮动黑度 double float_heidu; //黑度基准 double benchmarkBlk; //所有点最大黑度的平均值 double avgMax_heidu; //面积基准 double benchmarkAreaBlk; //黑度阀值 int heidu_fazhi; //字符区域黑点数的平均值 double char_area_black_avg[16]; }; class COnLineCardPageIdentifier { public: COnLineCardPageIdentifier(); ~COnLineCardPageIdentifier(); //识别指定图像 int Identify(const IplImage* img, void* out_result, int out_size); private: // 识别 int Identify(); //根据指定页面 int Identify_impl(); int BaseCheck(); int ClipImg(SchemaPage& schemaPage, IplImage * dst); int ReadQuestionScore(SchemaPage &schemaPage, IplImage * dst, CvMemStorage* storage); int ReadKeGuanTi1(SchemaPage &schemaPage, IplImage * dst); int ReadStudentID(SchemaPage &schemaPage, IplImage * dst); bool ReadQuekaoFlag(SchemaPage &schemaPage, IplImage * dst); void InitalizeTempVar(); //计算涂点属性 inline int caculate_cell_property(SchemaPage& schemaPage, SchemaItem &item, IplImage * dst, int &cellSize, double &refArea, double &avg_gray, int &grayNum, double &mo_hu_du, double &gao_heidu,/*字符区域大小*/int &char_area_size,/*字符区域黑色点数(统计选项的字符区域的灰度判定为黑色的点数,用于统计试卷该选项全局的平均字符黑点数)*/int& char_area_black_count,/*字符区域黑色点的平均灰度*/double& char_area_avg_gray, int flag = 0); //获取全局背景灰度,通过统计所有涂点周围像素(灰度不小于160)的灰度平均值获得 int caculate_global_background(SchemaPage& schemaPage, IplImage * dst, bool flag = false);//flag 检查学号 //分析全局属性 int analyseOmrPanoramic(SchemaPage& schemaPage); //根据分析结果生成结果字符串 int GenerateOmrStr(SchemaPage& schemaPage); int GetBlackArea(const IplImage * dst); int SaveLocateInfo(SchemaPage& schemaPage, std::vector &relationKey, std::vector &relationValue); inline int GetRect(const int centerx, const int centery, const int width, const int height, RESULT_RECT& result_rect); public: template void SaveRect(CvRect& rect, T& result); template inline CvRect GetCVRect(T& code) { CvRect result_rect; result_rect.x = code.centerx - code.width / 2; result_rect.y = code.centery - code.height / 2; result_rect.width = code.width; result_rect.height = code.height; return result_rect; } template inline void DrawObjRect(IplImage * dst, T& obj_result, CvScalar& scalar); inline int GetRect2(const int centerx, const int centery, const int width, const int height, RESULT_RECT& result_rect); BOOL FindQuestionLocatePoint(IplImage * dst, SchemaLocatePoint& lp1, CvPoint2D32f& point1); double GetDistance(CvPoint2D32f point1, CvPoint2D32f point2); int FindQuestionLocatePoints(SchemaPage& schemaPage, IplImage * dst); templateinline int GetTransformPoint(CvMat& mat, T& srcx, T& srcy, T& dstx, T& dsty){ dstx = (T)(CV_MAT_ELEM(mat, float, 0, 0)*srcx + CV_MAT_ELEM(mat, float, 0, 1)*srcy + CV_MAT_ELEM(mat, float, 0, 2)); dsty = (T)(CV_MAT_ELEM(mat, float, 1, 0)*srcx + CV_MAT_ELEM(mat, float, 1, 1)*srcy + CV_MAT_ELEM(mat, float, 1, 2)); return identify::result::IDF_SUCCESS; } int GetTianKongTiRedCount(IplImage * dst, const CvRect& rect_normal, const CvRect& rect_detect, int count, int multi); int GetZhuGuanTiRedCount(IplImage * dst, const CvRect& rect, const CvRect& normal_rect, int * red_counts, int * red_in_counts, int count, int multi,bool bTianKongTi=false); BOOL GetRedBinary(IplImage * dst, const CvRect& rect_detect, IplImage ** red_binary); int mycaculate_global_background(SchemaItem items[], int itemCount, IplImage * dst); int myanalyseOmrPanoramic(OnlineAnalyseResult& anlyseResultTemp, int count); int myGenerateOmrStr(OnlineAnalyseResult& anlyseResultTemp, int count); int ReadXuanZuoTi(SchemaPage& schemaPage, SchemaQuestionScore& qs, IplImage * dst); int GenerateOmrStr(SchemaPage& schemaPage, std::string &ret); void SetUseQr(std::string strQr, bool bUse); void SetOnlineScanType(int nOnlineScanType); void SetPaperMode(int mode); void SetIdentiforMode(int subject, int mode); void SetScanMode(int type); schema_const_param m_default_schema_param; int JiaoZheng_20200418(IplImage * src0, IplImage * &dst_img, const std::vector & top_locate_point_list, const std::vector & bottom_locate_point_list, const std::vector & word_location_point_list, int dir, double, double, int word_w, int word_h); int JiaoZheng_20200418_first(IplImage * src0, IplImage * &dst_img, const std::vector & top_locate_point_list, const std::vector & bottom_locate_point_list, const std::vector & word_location_point_list, int dir); int JiaoZheng_20200418_second_four(IplImage * src0_, IplImage * &dst_img, const std::vector & top_locate_point_list, const std::vector & bottom_locate_point_list, const std::vector & word_location_point_list, int dir); int JiaoZheng_20200418_second_five(IplImage * src0_, IplImage * &dst_img, const std::vector & top_locate_point_list, const std::vector & bottom_locate_point_list, const std::vector & word_location_point_list, int dir); int xuanzhuan(IplImage * src0, IplImage * &dst_img, CvRect myRect); void myscale_shema_param0(const schema_const_param& default_schema_const_param, schema_const_param& schema_param, double scale); void CalcPos(const Pos&pos, const CvPoint& offset, double w_scale, double h_scale, int ¢er_x, int ¢er_y, int &w, int &h); void InitScoreArea(SchemaQuestionScore&sqs, const ScoreBox&box, CvPoint offset, double w_scale, double h_scale); int createSchema(const IplImage* src, IplImage* *dst, SchemaPage* *pageSchema, const char * result_path, bool flag, std::string qr, bool bUseQr); OnLineCard::PaperTemplate* m_pTemplate; void SetTemplate(OnLineCard::PaperTemplate*pT); void SetPageDefault(SchemaPage& page); int OnLineCardJZ(IplImage* src, IplImage* &dst_img, int nPageIndex, int dir, std::vector&main_locate_point, int &wordloctlt); int MyFindDingWeiDian(IplImage * src_gray_img, CvMemStorage* storage, schema_const_param &schema_param, std::vector& locate_point_list, int & _dir); int MyFindBottomDingWeiDian(IplImage * src_gray_img, CvMemStorage* storage, schema_const_param &schema_param, std::vector& locate_point_list, int & _dir); int GetQrCode(IplImage* dst_gray_img, schema_const_param &schema_param, std::vector &main_locate_point, std::vector &codev, std::string& paper_id, std::string& student_code, int code_type); void DrawSchema(IplImage * dst_img, SchemaPage* & pageSchema); double CalcRectArea(IplImage* src, const std::vector & top_locate_point_list, const std::vector & bottom_locate_point_list); std::vector m_vecBottom; int obj_index; private: OnlineAnalyseResult anlyseResult; //源图像 IplImage *src; //纸张进入时的旋转角度 FeedDirection feedDirection; //模板 std::vector *schemaPages; std::vector m_relationKey; std::vector m_relationValue; int dianshu_meihaomi; bool m_bUseQr; int m_nOnlineScanType; std::string m_strQrClass; int m_scantype; int m_paper_mode; void* out_result; identify::result::OMR_RESULT* omr_result; int m_subjectMode; int m_identiforMode; private: //识别范围结果保存 std::vector item_result; float data[6]; std::vector m_question_locate_points; std::vector m_question_locate_point_found; std::vector m_items; public: RTL_CRITICAL_SECTION* m_althom_rcs; public: int m_nXianXiaDaFenType; bool m_nBxuanxiang; }; }