|
@@ -0,0 +1,563 @@
|
|
|
+#pragma once
|
|
|
+/********************************************************
|
|
|
+ * @file : public_define.h
|
|
|
+ * @brief : 公用的定义属性
|
|
|
+ * @details :
|
|
|
+ * @author : qqm
|
|
|
+ * @date : 2021-2-4
|
|
|
+*********************************************************/
|
|
|
+
|
|
|
+
|
|
|
+#include <iostream>
|
|
|
+#include <string>
|
|
|
+#include <vector>
|
|
|
+#include <map>
|
|
|
+#include <unordered_map>
|
|
|
+
|
|
|
+#if defined(_MSC_VER) || defined(_WIN32) || defined(_WIN64)
|
|
|
+#define dll_export __declspec(dllexport)
|
|
|
+#define dll_import __declspec(dllimport)
|
|
|
+#else // __linux__
|
|
|
+#define dll_export __attribute__ ((visibility("default")))
|
|
|
+#include <memory>
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+/// dll return value
|
|
|
+enum RETURN_VALUE {
|
|
|
+ RT_OK = 0, /// 正常
|
|
|
+ RT_ERROR = 1, /// 内部error
|
|
|
+ RT_UUID_EMPTY = 2, /// 批次号异常
|
|
|
+ RT_SAVE_PATH_EMPTY = 3, /// 保存路径异常
|
|
|
+ RT_TEMPLATE_EMPTY = 4, /// 模板为空
|
|
|
+ RT_HIMGS_LIST_EMPTY = 5, /// 图像列表异常
|
|
|
+ RT_HIMGS_LIST_NOT_DIV = 6, /// 图像列表不是模板整数被
|
|
|
+
|
|
|
+ /// 异常算法新增的异常类型
|
|
|
+ RT_ERROR_IMAGES_NOT_EQUAL_TPS = 7, /// 传入的答题卡个数跟模板个数不一致
|
|
|
+ RT_CHECK_ERROR = 8, /// 单份答题卡安全校验未通过
|
|
|
+ RT_CHECK_LCPTS_NOT_EQUAL_TPS = 9, /// 异常接口2传入的模板定位信息、答题卡定位信息、模板size不相等
|
|
|
+ RT_CHECK_LCPTINFO_ERROR = 10, /// 传入的定位信息不能满足矫正需求,成对数量<3
|
|
|
+ RT_CHECK_ONLINECARD_LCPT_ERROR = 11, /// 在线答题卡传入的定位点数量<3
|
|
|
+ RT_CHECK_LCPTINFO_XS_ERROR = 12, /// 传入的定位信息不能满足矫正需求,分布象限<3
|
|
|
+
|
|
|
+ /// 新增模板坐标僬侥
|
|
|
+ RT_TEMPLATE_BOX_ERROR = 20, /// 模板内的坐标越界或者无效
|
|
|
+};
|
|
|
+
|
|
|
+/// debug log leave 主要调式使用
|
|
|
+enum LOG_LEAVE{
|
|
|
+ LOG_AUTO = 0, /// log默认输出,正常接口默认值
|
|
|
+ LOG_FUN = 1, /// log所有流程中调用的函数 fun_xxx() in! ... fun_xxx() return!
|
|
|
+ LOG_KEYSTEP = 2, /// log所有的关键点步骤信息
|
|
|
+ LOG_DETAIL = 3, /// log关键点的具体值各个细节
|
|
|
+};
|
|
|
+
|
|
|
+/// 接口参数类型
|
|
|
+enum API_PARAM{
|
|
|
+ TYPE_ONLINE_CARD = 1, /// 在线答题卡
|
|
|
+ TYPE_THRID_CARD = 2, /// 第三方答题卡
|
|
|
+ NEED_OCR_SOCRE = 4, /// 需要识别分数
|
|
|
+ NO_NEED_OCR_SCORE= 8, /// 不需要识别分数
|
|
|
+ ERROR_CARD = 16, /// 异常答题卡 api_processing_error_images_hand 接口使用
|
|
|
+};
|
|
|
+
|
|
|
+/// 答题卡类型
|
|
|
+enum CARD_TYPE {
|
|
|
+ OLWS = TYPE_ONLINE_CARD | NEED_OCR_SOCRE, /// 在线 识别分数
|
|
|
+ OLNS = TYPE_ONLINE_CARD | NO_NEED_OCR_SCORE, /// 在线 不识别分数
|
|
|
+ TDWS = TYPE_THRID_CARD | NEED_OCR_SOCRE, /// 第三方 识别分数
|
|
|
+ TDNS = TYPE_THRID_CARD | NO_NEED_OCR_SCORE, /// 第三方 不识别分数
|
|
|
+ OLWSE = OLWS | ERROR_CARD, /// api_processing_error_images_hand接口类型
|
|
|
+ OLNSE = OLNS | ERROR_CARD,
|
|
|
+ TDWSE = TDWS | ERROR_CARD,
|
|
|
+ TDNSE = TDNS | ERROR_CARD,
|
|
|
+};
|
|
|
+
|
|
|
+/// 答题卡可能的状态信息 !!!有待完善设计
|
|
|
+enum PAPER_STATUS {
|
|
|
+ PAPER_SUCC = 0, /// SUCC
|
|
|
+ MISSED_LOCATION_POINT = 1, /// 定位点缺失
|
|
|
+ MISSED_LOCATION_AREA = 2, /// 定位区缺失
|
|
|
+ MISSED_LOCATION_CROSSPOINT = 4, /// 交叉点缺失
|
|
|
+ MATCH_FAILED = 8, /// 分页失败 模板不匹配
|
|
|
+ PROGRAM_ERROR = 16,/// 程序异常导致的失败
|
|
|
+ PAGEDISMISS = 32,/// 本份缺页
|
|
|
+ PAGEDATAERROR = 64,/// 本份图像异常
|
|
|
+};
|
|
|
+
|
|
|
+namespace preinfo {
|
|
|
+ /// 图像方向 逆时针方向
|
|
|
+ enum IMG_ROTATION {
|
|
|
+ ROTATION_0 = 1,
|
|
|
+ ROTATION_90 = 2,
|
|
|
+ ROTATION_180 = 4,
|
|
|
+ ROTATION_270 = 8,
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 图像&试题类型
|
|
|
+ enum BOX_TYPE
|
|
|
+ {
|
|
|
+ BOX_NONE, /// UNKNOW
|
|
|
+ BOX_ABSENCE_MARK, /// 缺考标记
|
|
|
+ BOX_BREAK_PRECEDENT, /// 违纪标记
|
|
|
+ BOX_EXAM_TT_NUMBER, /// 填涂考号
|
|
|
+ BOX_EXAM_QRCODE, /// 试卷二维码
|
|
|
+ BOX_EXAM_BARCODE, /// 试卷条码
|
|
|
+ BOX_QUESTION_CHOICE_S, /// 单项选择题
|
|
|
+ BOX_QUESTION_CHOICE_M, /// 不定项选择题
|
|
|
+ BOX_QUESTION_COMPLETION,/// 填空题
|
|
|
+ BOX_QUESETION_TF, /// 判断题
|
|
|
+ BOX_SUBJECTIVE_NORMAL, /// 普通主观题
|
|
|
+ BOX_SCORING_BOX, /// 线下阅卷的打分区
|
|
|
+ BOX_SUBJECTIVE_CHOOSE, /// 选做题
|
|
|
+ BOX_SUBJECTIVE_CHOOSE_COMBIN, /// 选做题-合并填涂
|
|
|
+ BOX_SUBJECTIVE_CHOOSE_SPLITE, /// 选做题-分离填涂
|
|
|
+ BOX_WRITE_CHINESE_COMPOSITION, /// 写作-语文作文
|
|
|
+ BOX_WRITE_ENGLISH_WRITING, /// 写作-英语写作
|
|
|
+
|
|
|
+ BOX_LOCATION_POINT, /// 定位点
|
|
|
+ BOX_LOCATION_AREA, /// 定位区
|
|
|
+ BOX_LOCATION_CROSS, /// 定位交叉点
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 方向
|
|
|
+ enum DIR_FLAG {
|
|
|
+ DIR_UNKNOW = -1,
|
|
|
+ DIR_UP = 1,
|
|
|
+ DIR_DOWN = 2,
|
|
|
+ DIR_LEFT = 4,
|
|
|
+ DIR_RIGHT = 8
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 填涂区域的方向
|
|
|
+ enum TT_DIR_FLAG {
|
|
|
+ TT_Y = 0, /// 垂直
|
|
|
+ TT_X = 1, /// 水平
|
|
|
+ };
|
|
|
+
|
|
|
+ template<typename T> struct TtSize{ ///
|
|
|
+ T width;
|
|
|
+ T height;
|
|
|
+ TtSize() :width(T(0)), height(T(0)) {};
|
|
|
+ };
|
|
|
+ template<typename T> struct PaperRect {
|
|
|
+ T centerx;
|
|
|
+ T centery;
|
|
|
+ T width;
|
|
|
+ T height;
|
|
|
+ T getX() const { return centerx - width / 2.0;}
|
|
|
+ T getY() const { return centery - height/ 2.0; }
|
|
|
+ PaperRect() :centerx(T(-1)), centery(T(-1)), width(T(0)), height(T(0)) {};
|
|
|
+ };
|
|
|
+ struct Field :PaperRect<double> {
|
|
|
+ int id; /// 一个唯一标识符 不可能有重复的
|
|
|
+ std::vector<int> vecTiHao; /// 整数题号 可以有重复
|
|
|
+ Field() :id(-1) {};
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 定位点
|
|
|
+ struct LocationPoint :Field {
|
|
|
+ BOX_TYPE type;
|
|
|
+ LocationPoint() :type(BOX_LOCATION_POINT) {};
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 定位区
|
|
|
+ struct LocationArea :Field {
|
|
|
+ BOX_TYPE type;
|
|
|
+ bool head; /// 是否是试卷名称区域
|
|
|
+ LocationArea() :head(false), type(BOX_LOCATION_AREA) {};
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 交叉点
|
|
|
+ struct LocationCrossPoint :Field {
|
|
|
+ BOX_TYPE type;
|
|
|
+ int sign; /// 交叉点开口方向
|
|
|
+ double angle;
|
|
|
+ LocationCrossPoint() :sign(DIR_UNKNOW), angle(0.0), type(BOX_LOCATION_CROSS) {};
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 条码/二维码
|
|
|
+ struct CodeInfo :Field {
|
|
|
+ BOX_TYPE type; /// BOX_EXAM_QRCODE or BOX_EXAM_BARCODE
|
|
|
+ TT_DIR_FLAG way;
|
|
|
+ CodeInfo() :type(BOX_EXAM_BARCODE), way(TT_X) {};
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 缺考标记
|
|
|
+ struct AbsenceMark:Field {
|
|
|
+ BOX_TYPE type;
|
|
|
+ AbsenceMark() :type(BOX_ABSENCE_MARK) {};
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 填涂考号
|
|
|
+ struct FillStuNumber:Field {
|
|
|
+ bool useable; /// 是否可用
|
|
|
+ TT_DIR_FLAG way; /// 水平/垂直
|
|
|
+ int cols; /// 列数
|
|
|
+ int rows; /// 行数
|
|
|
+ TtSize<double> itemSize; /// 单个小项宽高
|
|
|
+ double disx; /// 横向相邻的两个小项的x坐标的距离差
|
|
|
+ double disy; /// 纵向的........
|
|
|
+ FillStuNumber() :useable(false), way(TT_Y), cols(-1), rows(-1), disx(0.0), disy(0.0) {};
|
|
|
+ void init_dis() {
|
|
|
+ disx = (cols == 1) ? 0.0 : (width - itemSize.width) * 1.0 / (cols - 1) * 1.0;
|
|
|
+ disy = (rows == 1) ? 0.0 : (height - itemSize.height) * 1.0 / (rows - 1) * 1.0;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ /// 填涂考号 拆解到小项坐标
|
|
|
+ /// 填涂小项结构信息
|
|
|
+ struct TtItem :PaperRect<double> {
|
|
|
+ std::string optName; /// 0 ~ 9 A B C D .... 填涂
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 新逻辑 - 填涂考号
|
|
|
+ struct _FillStuNumber{
|
|
|
+ bool useable; /// 是否可用
|
|
|
+ int cols; /// 列数
|
|
|
+ int rows; /// 行数
|
|
|
+ std::map<int,std::vector<TtItem>> groups; /// pair<列序号(0开始),小项合集(从上到下)>
|
|
|
+ _FillStuNumber() : useable(false), cols(-1), rows(-1) { groups.clear(); };
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 新逻辑 - 填涂选做题 or 选择题
|
|
|
+ struct _QuestionChoice:Field{
|
|
|
+ BOX_TYPE type; /// BOX_QUESTION_CHOICE_S / M
|
|
|
+ int number; /// 填涂个数
|
|
|
+ TT_DIR_FLAG way; /// 方向
|
|
|
+ TtSize<double> itemSize; /// 单个小项宽高
|
|
|
+ std::vector<TtItem> groups; /// 组内的各个小项
|
|
|
+ _QuestionChoice():number(0),way(TT_X) {};
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 判断题
|
|
|
+ struct QuesetionTF:Field{
|
|
|
+ ;
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ /// 单个选择题
|
|
|
+ struct QuestionChoice:Field{
|
|
|
+ BOX_TYPE type; /// BOX_QUESTION_CHOICE_S / M
|
|
|
+ TT_DIR_FLAG way; /// 水平/垂直
|
|
|
+ TtSize<double> itemSize; /// 单个小项宽高
|
|
|
+ int number; /// 填涂项个数
|
|
|
+ std::vector<TtItem> groups; /// 组内的各个小项
|
|
|
+ QuestionChoice() :type(BOX_QUESTION_CHOICE_M), way(TT_X), number(0) {};
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 主观题的区域信息
|
|
|
+ struct SubjectiveField:Field{
|
|
|
+ BOX_TYPE type;
|
|
|
+ bool multiple; /// 是否多块
|
|
|
+ int orderNumber; /// 如果是多块 本块序号 从1开始
|
|
|
+ bool needConbin; /// 是否需要合并一起
|
|
|
+ int marktype; /// 如果等于4或者10则需要保留小图 2021.6.11 确认如果试题 如此切图
|
|
|
+ TT_DIR_FLAG way; /// 左右拼接 or 上下拼接
|
|
|
+ std::string name; /// 落地保存的文件名 e: "17" "22"
|
|
|
+ SubjectiveField() :type(BOX_SUBJECTIVE_NORMAL), multiple(false), orderNumber(1), needConbin(true), way(TT_Y), name("") {};
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 打分区
|
|
|
+ enum SCORE_TYPE {
|
|
|
+ NONE = 0, ///
|
|
|
+ NORMAL = 1, /// 一般的
|
|
|
+ COMBIN = 2, /// 组合型 个位&十位
|
|
|
+ QtCom = 3, /// 填空题
|
|
|
+ };
|
|
|
+ struct SocringArea:PaperRect<double> { /// 关联在 boxInfo下面 多块的只有ordernumber=0需要识别分数
|
|
|
+ bool ocr; /// 是否需要识别分数
|
|
|
+ int cols; /// 列数
|
|
|
+ SCORE_TYPE type;
|
|
|
+ bool withHalf; /// 是否含有.5分
|
|
|
+ int limit; /// 上限分值
|
|
|
+ double maxSocre; /// 小问最大分值
|
|
|
+ std::vector<double> vecSocreValue; /// 每个格子对应的数据 小于零的项不可用(个位&十位格子)
|
|
|
+ SocringArea() :cols(0), type(NONE),withHalf(false),ocr(false),limit(-1), maxSocre(-1.0){};
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 单个填空题
|
|
|
+ struct QuestionCompletion :SubjectiveField {
|
|
|
+ SocringArea scoreBox;
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 其他类型的box 只需要切割区域不需要额外操作的
|
|
|
+ struct BoxInfo :SubjectiveField {
|
|
|
+ SocringArea scoreBox;
|
|
|
+ BoxInfo() {};
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 选做题的标识符 每个选做题&选做题填涂 都有唯一的Key
|
|
|
+ struct SubjectiveChooseKey {
|
|
|
+ std::vector<int> vecIds; /// 选做题的id列表
|
|
|
+ std::vector<std::string> vecNames; /// 别名列表
|
|
|
+ int idx; /// 本块的序号 0 1 2 3 ...多选多的N序号
|
|
|
+ bool hbtt; /// 是否是合并填涂
|
|
|
+ int m; /// m选n
|
|
|
+ int n; /// m选n
|
|
|
+ bool operator == (const SubjectiveChooseKey & _k) {
|
|
|
+ return (_k.vecIds == vecIds) && (_k.idx == idx);
|
|
|
+ }
|
|
|
+ SubjectiveChooseKey() :idx(-1),hbtt(true) {};
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 选做题的区域信息
|
|
|
+ struct SubjectiveChooseField:SubjectiveField{
|
|
|
+ SubjectiveChooseKey key;
|
|
|
+ SocringArea scoreBox;
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 选做题的填涂判断信息
|
|
|
+ struct SubjectiveChooseTt:QuestionChoice{
|
|
|
+ SubjectiveChooseKey key;
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 新逻辑的填涂信息
|
|
|
+ struct _SubjectiveChooseTt : _QuestionChoice {
|
|
|
+ SubjectiveChooseKey key;
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 待定...
|
|
|
+ struct SubjectiveChoose { /// 选做题 分离&合并填涂 M选N
|
|
|
+ int m; /// 总数
|
|
|
+ int n; /// 选做个数
|
|
|
+ std::vector<int> ids; /// 题号列表
|
|
|
+ std::vector<SubjectiveChooseField> vecBoxes; /// 图像区域列表
|
|
|
+ std::vector<SubjectiveChooseTt> vecTt; /// 填涂区域列表
|
|
|
+
|
|
|
+ virtual void push_back(const SubjectiveField & sjtField) = 0;
|
|
|
+ };
|
|
|
+ struct Combin:public SubjectiveChoose{ /// 合并填涂
|
|
|
+
|
|
|
+ };
|
|
|
+ struct Splite:public SubjectiveChoose{ /// 分离填涂
|
|
|
+ Splite(const int & _m, const int & _n) {
|
|
|
+ ;
|
|
|
+ }
|
|
|
+ protected:
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 答题卡模板
|
|
|
+ typedef struct PaperTemplateInfo {
|
|
|
+ int index; /// 模板页的序号 从0开始
|
|
|
+ int width; ///
|
|
|
+ int height; ///
|
|
|
+
|
|
|
+ std::string strJsonPath; /// 模板json文件绝对路径
|
|
|
+ std::string strImgPath; /// 本张模板图像路径/URL
|
|
|
+ std::vector<BoxInfo> vecBoxes; /// 本张模板内主观题题目信息
|
|
|
+ std::vector<LocationPoint> vecLocaltionPoints; /// 定位点信息
|
|
|
+ std::vector<LocationArea> vecLocaltionAreas; /// 定位区信息
|
|
|
+ std::vector<LocationCrossPoint> vecLocationCross; /// 交叉点信息
|
|
|
+ std::vector<QuestionChoice> vecQtChoices; /// 选择题
|
|
|
+ std::vector<_QuestionChoice> _vecQtChoices; /// _选择题
|
|
|
+ std::vector<QuesetionTF> vecQtTf; /// 判断题
|
|
|
+ std::vector<QuestionCompletion> vecQtCompletion; /// 填空题
|
|
|
+ std::vector<AbsenceMark> vecAbsenceMark; /// 缺考&违纪
|
|
|
+ std::vector<CodeInfo> vecCodeBQ; /// 条码/ 二维码
|
|
|
+ std::vector<FillStuNumber> vecFillNumber; /// 填涂考号
|
|
|
+ std::vector<_FillStuNumber> _vecFillNumber; /// _填涂考号
|
|
|
+ std::vector<SubjectiveChooseField> vecXzBoxes; /// 选做题题目信息
|
|
|
+ std::vector<SubjectiveChooseTt> vecXzTtBoxes; /// 选做题填涂信息
|
|
|
+ std::vector<_SubjectiveChooseTt> _vecXzTtBoxes; /// 选做题填涂信息
|
|
|
+ void * ptrAreaFeatures; /// 定位区特征
|
|
|
+ } ptinfo;
|
|
|
+ typedef std::vector<PaperTemplateInfo> templatesInfo;
|
|
|
+
|
|
|
+ /// 选做题信息
|
|
|
+ struct XX {
|
|
|
+ std::vector<int> vecTiHao; ///! 必须是按照题号 升序排列
|
|
|
+ int m;
|
|
|
+ int n;
|
|
|
+ /**
|
|
|
+ 2022.1.19 题组实现逻辑
|
|
|
+ 问题:题组的结构是数量的N倍,与现有的逻辑冲突,但是如果把题组的题号拆分成两个
|
|
|
+ 选做题就可以实现,但是问题就是 第二块没有填涂区域,如何解决这个问题 ,
|
|
|
+ 方案:
|
|
|
+ 设定一个标识 判断是否使用其他题号的填涂判断结果
|
|
|
+ stealVecRes = true 则本题偷取 vecStealTiHao 的填涂结果
|
|
|
+ */
|
|
|
+ bool stealVecRes;
|
|
|
+ std::vector<int> vecStealTiHao;
|
|
|
+ XX() :m(0), n(0), stealVecRes(false) { vecStealTiHao.clear(); };
|
|
|
+ };
|
|
|
+
|
|
|
+ struct SubjChiInfo {
|
|
|
+ bool hasSplitTT;
|
|
|
+ bool hasCombinTT;
|
|
|
+ std::vector<XX> vecSptt;
|
|
|
+ std::vector<XX> vecCbtt;
|
|
|
+ SubjChiInfo() :hasSplitTT(false), hasCombinTT(false) {};
|
|
|
+ };
|
|
|
+
|
|
|
+ struct QtNumInfo {
|
|
|
+ std::vector<int> qtIds;
|
|
|
+ int qtNum;
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+namespace analysis {
|
|
|
+
|
|
|
+ /// 记录定位点 定位区 交叉点的查找情况
|
|
|
+ struct LocationResult
|
|
|
+ {
|
|
|
+ std::vector<preinfo::LocationPoint> vecLcpts; /// 图像找到的定位点
|
|
|
+ std::vector<preinfo::LocationArea> vecAreas; /// 图像找到的上的定位区
|
|
|
+ std::vector<preinfo::LocationCrossPoint> vecCrosses;/// 图像找到的上的交叉点
|
|
|
+
|
|
|
+ LocationResult() { vecLcpts.clear(); vecAreas.clear(); vecCrosses.clear(); }
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 每张答题卡的匹配结果
|
|
|
+ struct MatchResult {
|
|
|
+ bool matched; /// 是否匹配到了
|
|
|
+ PAPER_STATUS matchedStatus; /// 匹配过程中的状态记录
|
|
|
+ int matchedCount; /// 匹配到点数
|
|
|
+ int totalCount; /// 参与匹配的总数
|
|
|
+ int schemaIndex; /// 匹配到模板ID 从0开始
|
|
|
+ double scale; /// 与模板的比例系数
|
|
|
+ int dir; /// 方向
|
|
|
+ LocationResult lcRes; /// 定位信息结果
|
|
|
+ double transfrom[6]; /// 第三方的3*2矫正举证 模板-图像
|
|
|
+ double transfrom_[6]; /// 在线&第三方的3*2举证 图像-模板
|
|
|
+ bool nineUse; /// 是否优先使用3*3矩阵
|
|
|
+ double olctransfrom_[9]; /// 在线答题卡的3*3映射矩阵 图像-模板
|
|
|
+ MatchResult() { nineUse = false; matched = false; matchedStatus = PAPER_SUCC; matchedCount = 0; totalCount = 0; schemaIndex = -1; scale = -1; dir = 0; }
|
|
|
+ };
|
|
|
+ struct PageRes {
|
|
|
+ int idx;
|
|
|
+ preinfo::DIR_FLAG dir;
|
|
|
+ PageRes() { idx = -1; dir = preinfo::DIR_UNKNOW; }
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+namespace result {
|
|
|
+ /**
|
|
|
+ !所有填涂判断的起始值都是 -1 标识未填涂
|
|
|
+ */
|
|
|
+
|
|
|
+ enum ABSENT_MARK {
|
|
|
+ MARK_NORMAL = 0, /// 正常
|
|
|
+ MARK_ABSENCE = 1, /// 缺考
|
|
|
+ MARK_BREAK_PRECEDENT =2, /// 违纪
|
|
|
+ CHOICE_TOO_MUCH = 4, /// 单选题 填涂了全部
|
|
|
+ CHOICE_NONE = 8, /// 本题未填涂
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 填涂题目结果
|
|
|
+ struct ChoiceResult {
|
|
|
+ struct element {
|
|
|
+ int index; /// 按照从左到右/从上到下排列小项的下标 从-1开始 标识未填涂
|
|
|
+ double confidence; /// 置信度
|
|
|
+ element() :index(-1), confidence(0.0) {};
|
|
|
+ };
|
|
|
+ int id; /// 与模板的ID对应
|
|
|
+ int tiHao; /// 题号
|
|
|
+ ABSENT_MARK status; /// 本题的状态
|
|
|
+ int number; /// 本题小项个数
|
|
|
+ int mostCredible; /// 单选情况下 最可信的ID下标
|
|
|
+ std::vector<std::string> vecOpts; /// 本题结果选项是哪一个
|
|
|
+ preinfo::BOX_TYPE type; /// 多选还是单选
|
|
|
+ std::vector<bool> vecRes;/// _看需求 是否启用 true:填涂了 false:未填涂
|
|
|
+ std::vector<element> vecIdx;/// 备选方案
|
|
|
+ ChoiceResult() :id(-1),tiHao(-1), status(MARK_NORMAL), number(0), type(preinfo::BOX_QUESTION_CHOICE_M) {};
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 判断题
|
|
|
+ struct QTFRes {
|
|
|
+ int id;
|
|
|
+ bool fill;
|
|
|
+ QTFRes() :id(-1), fill(false) {};
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 主观题题目
|
|
|
+ struct SubjectiveResult {
|
|
|
+ struct IMG_INFO {
|
|
|
+ std::vector<unsigned char> imgData;
|
|
|
+ bool vaild;
|
|
|
+ int cols;
|
|
|
+ int rows;
|
|
|
+ int channel;
|
|
|
+ IMG_INFO() :vaild(false), cols(0), rows(0), channel(0) {};
|
|
|
+ };
|
|
|
+ int id; /// 不是题号 是一个UUID雷士的东西
|
|
|
+ std::vector<int> uuids; /// 多块合并的图像,是可能有多个UUID的 2022.1.19 新增
|
|
|
+ int th; /// 本题的题号
|
|
|
+ std::vector<int> tiHao; /// 选做题适用
|
|
|
+ bool multiple; /// 是否多块
|
|
|
+ int orderNumber; /// 如果是多块 本块序号 默认从1开始 如果是合并得到图则 ordernumber=-1
|
|
|
+ double score; /// 分数
|
|
|
+ preinfo::BOX_TYPE type; /// BOX TYPE
|
|
|
+ int marktype; /// 是否保存分块的小图 只有4和10保留
|
|
|
+ int idx; /// 只有type=选做题时候有效
|
|
|
+ IMG_INFO img; /// 线下阅卷问题 预留方案
|
|
|
+ /*
|
|
|
+ 2022.1.19 改动 多个小块的图像有可能有多个打分框 所以要做支持
|
|
|
+ 改动记录:
|
|
|
+ 由 vector<int> 改动到 unordered_map<int, std::vector<int>> ,int = uuid 作为唯一关联key值
|
|
|
+ **/
|
|
|
+ std::vector<int> sr; /// 分数判断结果 内容:红色批改的框的红色值 个数:所有小框数量和
|
|
|
+ std::unordered_map<int, std::vector<int>> mapSr; /// 记录每个uuid对应的打分框的识别结果
|
|
|
+
|
|
|
+ std::string path; /// 绝对路径
|
|
|
+ std::string name; /// 落地文件名
|
|
|
+ int width; /// 2021.4.24 需求需要提供主观题的宽高信息
|
|
|
+ int height; /// ...
|
|
|
+ SubjectiveResult() :id(-1), multiple(false), orderNumber(1),marktype(0),
|
|
|
+ score(0.0),idx(-1), type(preinfo::BOX_NONE), path(""), name(""), width(0),height(0) {};
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 选做题
|
|
|
+ struct SubjectiveChooseResult{
|
|
|
+ preinfo::SubjectiveChooseKey key;
|
|
|
+ preinfo::BOX_TYPE type;
|
|
|
+ int id;
|
|
|
+ int tIdx; /// 选中的下标 0:可能是未填涂默认值 也有可能是填涂了第一个
|
|
|
+ std::string path; /// 绝对路径
|
|
|
+ std::string name; /// 文件名
|
|
|
+ double score; /// 分数
|
|
|
+ SubjectiveChooseResult() :type(preinfo::BOX_SUBJECTIVE_CHOOSE), id(-1), tIdx(-1), path(""), name(""), score(0.0) {};
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 选做题结果简单记录
|
|
|
+ struct SubjChResRecord {
|
|
|
+ std::vector<int> vecTiHaos;
|
|
|
+ int m; int n;
|
|
|
+ preinfo::BOX_TYPE type;
|
|
|
+ std::vector<int> vecRes;
|
|
|
+ };
|
|
|
+
|
|
|
+ /// 识别的单份答题卡结果
|
|
|
+ typedef struct SinglePaperInfo {
|
|
|
+ int orderNumber; /// 本份的序号 备注:orderNumber = totalNumbers/mb.size()
|
|
|
+ bool last; /// 是否本批次最后一份
|
|
|
+ int idx; /// 如果状态是异常,标明那一张答题卡出现了异常,下标0开始 备注:首先判断status的状态
|
|
|
+ int numbers; /// 本份页数 备注:理论上等于模板的张数
|
|
|
+ int choiceNumbers; /// 所有填涂题目个数 备注:所有选择题总数量
|
|
|
+ PAPER_STATUS status; /// 本份试卷状态标志 备注:见枚举定义
|
|
|
+ ABSENT_MARK absent; /// 缺考 or 违纪 备注:见枚举定义
|
|
|
+ std::string barCode; /// 条码识别结果 备注:条形码识别结果 仅仅是条形码结果
|
|
|
+ std::string qrCode; /// 二维码识别结果 备注:二维码识别结果 空值只能标明未识别到或者没有条码 条码也适用
|
|
|
+ std::string fillNumber; /// 填涂考号 备注:长度=模板设定考号列数,未填涂位置用' '空格填充 !!!重要
|
|
|
+ std::string strSavePath; /// 本份的保存路径 备注:备份的保存路径下面会有 xx.jpg xx_.jpg等等图像
|
|
|
+ std::vector<std::string> vecUrlPath; /// 图像的本地路径 备注:客户端需求添加
|
|
|
+ std::vector<std::string> vecUrlAPath; /// 矫正后的原图路径 备注:矫正后的图,顺序为 img_1.jpg img_2.jpg ... 不超过模板张数
|
|
|
+ std::vector<QTFRes> tfRes; /// 判断题 备注:该类型未实现
|
|
|
+ std::vector<ChoiceResult> choiceRes; /// 所有填涂题目结果 备注:使用tiHao(int) 和 vecOpts(判断结果)即可 ,单选题vecOpts可能是一个或者全部数量(对应全部填涂错误)多选择是真实个数
|
|
|
+ std::shared_ptr<ChoiceResult> ptrChoiceRes; /// 所有填涂题目结果 备注:未启用 请忽略
|
|
|
+ std::vector<SubjectiveResult> subjectiveRes; /// 主观题 备注:所有主观题(填空,解答,选做等等)都在这里面 th标识本题最终输出结果
|
|
|
+ std::shared_ptr<SubjectiveResult> ptrSubjective; /// ...... 备注:未启用 请忽略
|
|
|
+ std::vector<SubjChResRecord> subjectiveCRes; /// 选做题 备注:存放选择题判断结果 内部使用请忽略
|
|
|
+ std::shared_ptr<SubjChResRecord> ptrSubjectiveC; /// 备注:未启用 请忽略
|
|
|
+ std::vector<analysis::LocationResult> vecLcRes; /// 定位信息的结果保存 备注:与 vecUrlPath 一一对应
|
|
|
+ SinglePaperInfo() :orderNumber(-1), last(false), idx(-1), numbers(0), choiceNumbers(0), status(PAPER_SUCC), absent(MARK_NORMAL),
|
|
|
+ barCode(""), qrCode(""), fillNumber(""), strSavePath("") {};
|
|
|
+ }spinfo;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|