#include "stdafx.h" #include "OnLineCardPageIdentifier.h" #include "OnLineCardSchemaStruct.h" #include "schema_struct.h" #include "schema_struct_auto.h" #include #include #include #include #include #include "GrayImageSource.h" #include #include #include #include #include #include #include #include "schema_struct.h" #include #include <..\zxinglib\zxing\ReaderException.h> #include "Util.h" #include "../lib/myqr/include/GetQRCode.h" #include "opencv2/opencv.hpp" #include #include #include "ParseQRInfo.h" /******************************************************** * @function : * @brief : 红色分析判断的客户端交互接口(阶段1:实现红色像素的数量统计 阶段2:实现红色的形状判断 目前只实现阶段1 * @input : Mat img_input; // 切割好的打分框区域 精准区域 int cols; // 该打分框的个数 int type; // 打分框所属(非在线模板解答0 非在线模板填空1 在线模板解答2 在线模板填空3 ) int mutil: // 是否是组合型包含(个位+十位) 打分框 int * a_res; // 存放结果的数组 int len; // a_res的长度 len应该等于cols * @output : int ret; // 0: succ 1: faild 2: img.empty||img.error * @return : int ret; * @author : Duste 2020/03/27 10:07 * @History : *********************************************************/ __declspec(dllimport) int api_red_check_analysis(cv::Mat&img, int cols, int type, int mutil, int * arr_result, int arr_len); /******************************************************** * @function : * @brief : DTK的定位点查找 * @input : @见函数说明 给定图像+模板定位点位置信息, * @output : * @return : int,(0:succ) (-1:input error) (-2:img.empty||img type.error) (-3:not found) * @author : Duste 2020/07/02 15:33 * @History : *********************************************************/ int api_location_anchor_points(const cv::Mat&img_gray, // 输入的灰度图像 const std::vector&vec_lcpts, // json内的定位点信息 const cv::Size&mb_size, // json内模板图像的宽高 std::vector&vec_tops, // 接受找到的上面三个定位点 下标访问 std::vector&vec_bottoms, // 接受找到的下面的两个定位点 下标访问 std::vector&vec_len, // 解决不同版本内存权限问题 int&dir, // 接受识别到的本图像的方向(0123-上下左右) int top_number, // 知心慧学 top_number=3或4 在线模板 top_number=3 int need_bottom // 是否需要查找bottom定位点 );// Vec_lcpts: json内的两页内所有的定位点的矩形信息合集 #if _DEBUG #pragma comment(lib,"../lib/myqr/debug/GetQR.lib") #pragma comment(lib,"../Win32/Debug/client_interactive_api_d.lib") #else #pragma comment(lib,"../lib/myqr/Release/GetQR.lib") #pragma comment(lib,"../Win32/Release/client_interactive_api.lib") #endif using namespace cv; using namespace std; using namespace zxing; namespace OnLineCard{ enum SelectType{ //未选中 UNSELECT, //不确定 UNCERTAIN, //选中 SELECTED }; #define MAX_ITEM 64 enum { JIEDATITYPE = 0, TIANKONGTITYPE = 1, }; void SetTBLR(SchemaQuestionScore& score) { score.lt.x = score.lb.x = (int)(0.5 + score.centerx - score.width / 2.0); score.rt.x = score.rb.x = (int)(0.5 + score.centerx + score.width / 2.0); score.lt.y = score.rt.y = (int)(0.5 + score.centery - score.height / 2.0); score.lb.y = score.rb.y = (int)(0.5 + score.centery + score.height / 2.0); } COnLineCardPageIdentifier::COnLineCardPageIdentifier() { m_pTemplate = nullptr; src = NULL; feedDirection = ROTATE_0; m_strQrClass = ""; m_bUseQr = false; } COnLineCardPageIdentifier::~COnLineCardPageIdentifier() { } // 识别 int COnLineCardPageIdentifier::Identify() { try{ int r = Identify_impl(); if (r == identify::result::IDF_SUCCESS){ omr_result->identified = TRUE; omr_result->identify_msg = "识别成功"; return r; } }catch (std::exception &e){ return identify::result::IDF_FAILURE; } return identify::result::IDF_CANNOT_MATCH_TEMPLATE; } void COnLineCardPageIdentifier::SetScanMode(int type) { m_scantype = type; } void COnLineCardPageIdentifier::SetUseQr(std::string strQr, bool bUse) { m_bUseQr = bUse; m_strQrClass = strQr; } void COnLineCardPageIdentifier::SetPaperMode(int mode) { m_paper_mode = mode; } void COnLineCardPageIdentifier::SetIdentiforMode(int subject, int mode) { m_subjectMode = subject; m_identiforMode = mode; } #define ROUND_SCALE(x) ((int)(x*scale+0.5)) #define ROUND_SCALE_ARRAY(_dst,_src,count) \ for (int i=0;idepth, src0->nChannels); cvCopy(src0, result, NULL); cvResetImageROI(src0); dst_img = cvCreateImage(cvSize(myRect.height, myRect.width), src0->depth, src0->nChannels); cvTranspose(result, dst_img); cvFlip(dst_img, NULL, 1); cvReleaseImage(&result); return identify::result::IDF_SUCCESS; } inline int get_distance(CvPoint2D32f p1, CvPoint2D32f p2){ double dy = p2.y - p1.y; double dx = p2.x - p1.x; return static_cast(sqrt(dx*dx + dy*dy)); } // 纠偏后的新坐标点 CvPoint2D32f get_new_point(CvPoint2D32f ptOld, int iWidth, int iHight, float thir) { // 转图像中心坐标系 CvPoint2D32f ptNew, ptNew_, ptOld_; CvPoint2D32f ptMid = cvPoint2D32f(iWidth / 2.0, iHight / 2.0); ptOld_.x = ptOld.x - ptMid.x; ptOld_.y = -(ptOld.y - ptMid.y); float thetia = atan2(float(ptOld_.y), float(ptOld_.x)); float angleOld = static_cast( thetia * 180.0 / CV_PI); float angleNew = angleOld - thir; double dx = cos(angleNew*CV_PI / 180.0)*ptOld_.y / sin(angleOld*CV_PI / 180.0); double dy = sin(angleNew*CV_PI / 180.0)*ptOld_.y / sin(angleOld*CV_PI / 180.0); ptNew_.x = dx > 0 ? (dx + 0.5) : (dx - 0.5); ptNew_.y = dy > 0 ? (dy + 0.5) : (dy - 0.5); // 转回原坐标系坐标 // 这里需要重新计算 中心点坐标(计算四个顶点后计算外接矩形再确定中心点) // 这里简化处理 因为只需要处理 90,180,270,等固定角度旋转 if (90 == abs(thir) || 270 == abs(thir)) ptMid = cvPoint2D32f(iHight / 2.0, iWidth / 2.0); ptNew.x = ptNew_.x + ptMid.x; ptNew.y = ptMid.y - ptNew_.y; return ptNew; } bool sort_locate_point_by_x_pt2f(const CvPoint2D32f c1, const CvPoint2D32f c2) { return c1.x < c2.x; } inline void sort_point_list(CvPoint2D32f * points_src){ int max_y = std::max(std::max(points_src[0].y, points_src[1].y), points_src[2].y); vector vec_one, vec_two; for (int i = 0; i < 3; i++) { CvPoint2D32f tmp = points_src[i]; if (tmp.y > max_y / 2) vec_two.push_back(tmp); else vec_one.push_back(tmp); } std::sort(vec_one.begin(), vec_one.end(), sort_locate_point_by_x_pt2f); for (std::size_t i = 0; i < vec_one.size(); i++) points_src[i] = vec_one[i]; points_src[vec_one.size()] = vec_two[0]; return; } inline cv::Mat IplImageToMat(const IplImage* image, bool copyData = false) { if (!image) return cv::Mat(); int imageDepth = IPL2CV_DEPTH(image->depth); int type = CV_MAKETYPE(imageDepth, image->nChannels); cv::Mat ret(image->height, image->width, type, image->imageData, image->widthStep); return copyData ? ret.clone() : ret; } int COnLineCardPageIdentifier::JiaoZheng_20200418_first(IplImage * src0_, IplImage * &dst_img, const vector & top_locate_point_list, const vector & bottom_locate_point_list, const vector & word_location_point_list, int dir) { // printf("线程:%s JiaoZheng_20200418_first1 \n", std::to_string(GetCurrentThreadId()).c_str()); int bottom_id = 0; if (3 == dir) bottom_id = 1; CvPoint2D32f points_src[3] = { cvPoint2D32f(top_locate_point_list[0].x + top_locate_point_list[0].width / 2.0, top_locate_point_list[0].y + top_locate_point_list[0].height / 2.0), cvPoint2D32f(top_locate_point_list[top_locate_point_list.size() - 1].x + top_locate_point_list[top_locate_point_list.size() - 1].width / 2.0, top_locate_point_list[top_locate_point_list.size() - 1].y + top_locate_point_list[top_locate_point_list.size() - 1].height / 2.0), cvPoint2D32f(bottom_locate_point_list[bottom_id].x + bottom_locate_point_list[bottom_id].width / 2.0, bottom_locate_point_list[bottom_id].y + bottom_locate_point_list[bottom_id].height / 2.0) }; IplImage * src0 = nullptr; // printf("线程:%s JiaoZheng_20200418_first2 \n", std::to_string(GetCurrentThreadId()).c_str()); try{ src0 = cvCloneImage(src0_); } catch (cv::Exception&e){ // printf("线程:%s cvCloneImage %s\n", std::to_string(GetCurrentThreadId()).c_str(), e.what()); } // printf("线程:%s JiaoZheng_20200418_first3 \n", std::to_string(GetCurrentThreadId()).c_str()); // 0:上 旋转0度 1:下 旋转180度 2:左 旋转90度 3:右 旋转270度 如果不对请自行调整 CvPoint2D32f points_src_rotate[3] = { points_src[0], points_src[1], points_src[2] }; // printf("线程:%s JiaoZheng_20200418_first cvCreateImage dir=%d %d %d %d %d \n", std::to_string(GetCurrentThreadId()).c_str(), dir, src0->width, src0->height, src0->depth, src0->nChannels); float angle = 0.0; if (0 == dir) { angle = 0.0; dst_img = cvCreateImage(cvSize(src0->width, src0->height), src0->depth, src0->nChannels); } else if (1 == dir){ angle = 180; //cvFlip(src0,src0,1); dst_img = cvCreateImage(cvSize(src0->width, src0->height), src0->depth, src0->nChannels); } else if (2 == dir) { angle = 90; dst_img = cvCreateImage(cvSize(src0->height, src0->width), src0->depth, src0->nChannels); } else if (3 == dir) { angle = 270; dst_img = cvCreateImage(cvSize(src0->height, src0->width), src0->depth, src0->nChannels); } else return identify::result::IDF_FAILURE; // printf("线程:%s JiaoZheng_20200418_first cvCreateImage end \n", std::to_string(GetCurrentThreadId()).c_str()); if (angle > 1.0){ for (int i = 0; i < 3; i++){ points_src_rotate[i] = get_new_point(points_src_rotate[i], src0->width, src0->height, angle); } } // printf("线程:%s JiaoZheng_20200418_first4 \n", std::to_string(GetCurrentThreadId()).c_str()); CvPoint2D32f points_dst[3]; for (int i = 0; i < 3; i++){ CvPoint2D32f pt_src_tmp = points_src_rotate[i]; int nearst_id = -1; int nearst_distance = 100000000; for (std::size_t j = 0; j < word_location_point_list.size(); j++){ CvPoint2D32f pt_dst_tmp = cvPoint2D32f(word_location_point_list[j].x + word_location_point_list[j].width / 2.0, word_location_point_list[j].y + word_location_point_list[j].height / 2.0); int distance = get_distance(pt_src_tmp, pt_dst_tmp); if (distance < nearst_distance){ nearst_distance = distance; nearst_id = j; } } if (-1 == nearst_id) return identify::result::IDF_FAILURE; points_dst[i] = cvPoint2D32f(word_location_point_list[nearst_id].x + word_location_point_list[nearst_id].width / 2.0, word_location_point_list[nearst_id].y + word_location_point_list[nearst_id].height / 2.0);; } // printf("线程:%s JiaoZheng_20200418_first5 \n", std::to_string(GetCurrentThreadId()).c_str()); CvMat * warp_mat = cvCreateMat(2, 3, CV_32FC1); cvGetAffineTransform(points_src, points_dst, warp_mat); cvWarpAffine(src0, dst_img, warp_mat, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvScalarAll(255)); cvReleaseMat(&warp_mat); #if _DEBUG cvSaveImage("D:\\show\\1.png", src0); cvSaveImage("D:\\show\\2.png", dst_img); #endif cvReleaseImage(&src0); // printf("线程:%s JiaoZheng_20200418_first6 \n", std::to_string(GetCurrentThreadId()).c_str()); return identify::result::IDF_SUCCESS; } int COnLineCardPageIdentifier::JiaoZheng_20200418_second_four(IplImage * src0_, IplImage * &dst_img, const vector & top_locate_point_list, const vector & bottom_locate_point_list, const vector & word_location_point_list, int dir) { //CV_Assert(top_locate_point_list.size()>2); //CV_Assert(bottom_locate_point_list.size()); CvPoint2D32f points_src[4] = { cvPoint2D32f(top_locate_point_list[0].x + top_locate_point_list[0].width / 2.0, top_locate_point_list[0].y + top_locate_point_list[0].height / 2.0), cvPoint2D32f(top_locate_point_list[top_locate_point_list.size() - 1].x + top_locate_point_list[top_locate_point_list.size() - 1].width / 2.0, top_locate_point_list[top_locate_point_list.size() - 1].y + top_locate_point_list[top_locate_point_list.size() - 1].height / 2.0), cvPoint2D32f(bottom_locate_point_list[0].x + bottom_locate_point_list[0].width / 2.0, bottom_locate_point_list[0].y + bottom_locate_point_list[0].height / 2.0), cvPoint2D32f(bottom_locate_point_list[1].x + bottom_locate_point_list[1].width / 2.0, bottom_locate_point_list[1].y + bottom_locate_point_list[1].height / 2.0) }; IplImage * src0 = cvCloneImage(src0_); // 0:上 旋转0度 1:下 旋转180度 2:左 旋转90度 3:右 旋转270度 如果不对请自行调整 CvPoint2D32f points_src_rotate[4] = { points_src[0], points_src[1], points_src[2], points_src[3] }; float angle = 0.0; if (0 == dir) { angle = 0.0; dst_img = cvCreateImage(cvSize(src0->width, src0->height), src0->depth, src0->nChannels); } else if (1 == dir){ angle = 180; //cvFlip(src0,src0,1); dst_img = cvCreateImage(cvSize(src0->width, src0->height), src0->depth, src0->nChannels); } else if (2 == dir) { angle = 90; dst_img = cvCreateImage(cvSize(src0->height, src0->width), src0->depth, src0->nChannels); } else if (3 == dir) { angle = 270; dst_img = cvCreateImage(cvSize(src0->height, src0->width), src0->depth, src0->nChannels); } else return identify::result::IDF_FAILURE; if (angle > 1.0){ for (int i = 0; i < 4; i++){ points_src_rotate[i] = get_new_point(points_src_rotate[i], src0->width, src0->height, angle); } } CvPoint2D32f points_dst[4]; for (std::size_t i = 0; i < 4; i++){ CvPoint2D32f pt_src_tmp = points_src_rotate[i]; int nearst_id = -1; int nearst_distance = 100000000; for (std::size_t j = 0; j < word_location_point_list.size(); j++){ CvPoint2D32f pt_dst_tmp = cvPoint2D32f(word_location_point_list[j].x + word_location_point_list[j].width / 2.0, word_location_point_list[j].y + word_location_point_list[j].height / 2.0); int distance = get_distance(pt_src_tmp, pt_dst_tmp); if (distance < nearst_distance){ nearst_distance = distance; nearst_id = j; } } if (-1 == nearst_id) return identify::result::IDF_FAILURE; points_dst[i] = cvPoint2D32f(word_location_point_list[nearst_id].x + word_location_point_list[nearst_id].width / 2.0, word_location_point_list[nearst_id].y + word_location_point_list[nearst_id].height / 2.0);; } Point2f pts[4]; for (int i = 0; i < 4; i++) pts[i] = Point2f(points_src[i].x, points_src[i].y); Point2f ptd[4]; for (int i = 0; i < 4; i++) ptd[i] = Point2f(points_dst[i].x, points_dst[i].y); cv::Mat warp_mat(cv::Size(3, 3), CV_32FC1); warp_mat = getPerspectiveTransform(pts, ptd); CvMat b = warp_mat; cvWarpPerspective(src0_, dst_img, &b, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvScalarAll(255)); #if _DEBUG cvSaveImage("D:\\show\\1.png", src0); cvSaveImage("D:\\show\\2.png", dst_img); #endif cvReleaseImage(&src0); return identify::result::IDF_SUCCESS; } int COnLineCardPageIdentifier::JiaoZheng_20200418_second_five(IplImage * src0_, IplImage * &dst_img, const vector & top_locate_point_list, const vector & bottom_locate_point_list, const vector & word_location_point_list, int dir) { //CV_Assert(top_locate_point_list.size()>2); //CV_Assert(bottom_locate_point_list.size()); CvPoint2D32f points_src[5] = { cvPoint2D32f(top_locate_point_list[0].x + top_locate_point_list[0].width / 2.0, top_locate_point_list[0].y + top_locate_point_list[0].height / 2.0), cvPoint2D32f(top_locate_point_list[1].x + top_locate_point_list[1].width / 2.0, top_locate_point_list[1].y + top_locate_point_list[1].height / 2.0), cvPoint2D32f(top_locate_point_list[top_locate_point_list.size() - 1].x + top_locate_point_list[top_locate_point_list.size() - 1].width / 2.0, top_locate_point_list[top_locate_point_list.size() - 1].y + top_locate_point_list[top_locate_point_list.size() - 1].height / 2.0), cvPoint2D32f(bottom_locate_point_list[0].x + bottom_locate_point_list[0].width / 2.0, bottom_locate_point_list[0].y + bottom_locate_point_list[0].height / 2.0), cvPoint2D32f(bottom_locate_point_list[1].x + bottom_locate_point_list[1].width / 2.0, bottom_locate_point_list[1].y + bottom_locate_point_list[1].height / 2.0) }; IplImage * src0 = cvCloneImage(src0_); // 0:上 旋转0度 1:下 旋转180度 2:左 旋转90度 3:右 旋转270度 如果不对请自行调整 CvPoint2D32f points_src_rotate[5] = { points_src[0], points_src[1], points_src[2], points_src[3], points_src[4] }; float angle = 0.0; if (0 == dir) { angle = 0.0; dst_img = cvCreateImage(cvSize(src0->width, src0->height), src0->depth, src0->nChannels); } else if (1 == dir){ angle = 180; //cvFlip(src0,src0,1); dst_img = cvCreateImage(cvSize(src0->width, src0->height), src0->depth, src0->nChannels); } else if (2 == dir) { angle = 90; dst_img = cvCreateImage(cvSize(src0->height, src0->width), src0->depth, src0->nChannels); } else if (3 == dir) { angle = 270; dst_img = cvCreateImage(cvSize(src0->height, src0->width), src0->depth, src0->nChannels); } else return identify::result::IDF_FAILURE; if (angle > 1.0){ for (int i = 0; i < 5; i++){ points_src_rotate[i] = get_new_point(points_src_rotate[i], src0->width, src0->height, angle); } } CvPoint2D32f points_dst[5]; for (std::size_t i = 0; i < 5; i++){ CvPoint2D32f pt_src_tmp = points_src_rotate[i]; int nearst_id = -1; int nearst_distance = 100000000; for (std::size_t j = 0; j < word_location_point_list.size(); j++){ CvPoint2D32f pt_dst_tmp = cvPoint2D32f(word_location_point_list[j].x + word_location_point_list[j].width / 2.0, word_location_point_list[j].y + word_location_point_list[j].height / 2.0); int distance = get_distance(pt_src_tmp, pt_dst_tmp); if (distance < nearst_distance){ nearst_distance = distance; nearst_id = j; } } if (-1 == nearst_id) return identify::result::IDF_FAILURE; points_dst[i] = cvPoint2D32f(word_location_point_list[nearst_id].x + word_location_point_list[nearst_id].width / 2.0, word_location_point_list[nearst_id].y + word_location_point_list[nearst_id].height / 2.0);; } Point2f pts[5]; for (int i = 0; i < 5; i++) pts[i] = Point2f(points_src[i].x, points_src[i].y); Point2f ptd[5]; for (int i = 0; i < 5; i++) ptd[i] = Point2f(points_dst[i].x, points_dst[i].y); cv::Mat warp_mat(cv::Size(3, 3), CV_32FC1); warp_mat = getPerspectiveTransform(pts, ptd); CvMat b = warp_mat; cvWarpPerspective(src0_, dst_img, &b, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvScalarAll(255)); #if _DEBUG cvSaveImage("D:\\show\\1.png", src0); cvSaveImage("D:\\show\\2.png", dst_img); #endif cvReleaseImage(&src0); return identify::result::IDF_SUCCESS; } int COnLineCardPageIdentifier::JiaoZheng_20200418(IplImage * src0, IplImage * &dst_img, const vector & top_locate_point_list, const vector & bottom_locate_point_list, const vector & word_location_point_list, int dir, double scale_x, double scale_y, int word_w, int word_h) { int len_l = top_locate_point_list.size(); if (len_l != 3 || bottom_locate_point_list.size() != 2) return identify::result::IDF_FAILURE; // 中心点 CvPoint2D32f points_src_[3] = { cvPoint2D32f(top_locate_point_list[0].x + top_locate_point_list[0].width / 2.0, top_locate_point_list[0].y + top_locate_point_list[0].height / 2.0), cvPoint2D32f(top_locate_point_list[len_l - 1].x + top_locate_point_list[len_l - 1].width / 2.0, top_locate_point_list[len_l - 1].y + top_locate_point_list[len_l - 1].height / 2.0), cvPoint2D32f(bottom_locate_point_list[0].x + bottom_locate_point_list[0].width / 2.0, bottom_locate_point_list[0].y + bottom_locate_point_list[0].height / 2.0) }; cv::Size location_size[3] = { cvSize(top_locate_point_list[0].width, top_locate_point_list[0].height), cvSize(top_locate_point_list[len_l - 1].width, top_locate_point_list[len_l - 1].height), cvSize(bottom_locate_point_list[0].width, bottom_locate_point_list[0].height) }; // 0:上 旋转0度 1:下 旋转180度 2:左 旋转90度 3:右 旋转270度 如果不对请自行调整 CvPoint2D32f points_src_rotate[3] = { points_src_[0], points_src_[1], points_src_[2] }; float angle = 0.0; int use_w = src0->width; int use_h = src0->height; if (0 == dir) { angle = 0.0; } else if (1 == dir){ angle = 180; } else if (2 == dir) { angle = 90; swap(use_w, use_h); for (int i = 0; i < 3; i++) swap(location_size[i].width, location_size[i].height); } else if (3 == dir) { angle = 270; swap(use_w, use_h); for (int i = 0; i < 3; i++) swap(location_size[i].width, location_size[i].height); } else return identify::result::IDF_FAILURE; if (angle > 1.0){ for (int i = 0; i < 3; i++){ points_src_rotate[i] = get_new_point(points_src_rotate[i], src0->width, src0->height, angle); } } // 按照从左到右 从上到下 排序 sort_point_list(points_src_rotate); // 推算边缘点 CvPoint2D32f points_src[3] = { cvPoint2D32f(points_src_rotate[0].x - (location_size[0].width / 2.0 + 0.55), top_locate_point_list[0].y - (location_size[0].height / 2.0 + 0.55)), cvPoint2D32f(points_src_rotate[1].x + (location_size[1].width / 2.0 + 0.55), top_locate_point_list[1].y - (location_size[1].height / 2.0 + 0.55)), cvPoint2D32f(points_src_rotate[2].x - (location_size[2].width / 2.0 + 0.55), top_locate_point_list[2].y + (location_size[2].height / 2.0 + 0.55)) }; // 寻找json数据的对应定位点坐标 CvPoint2D32f points_dst_[3]; // 中心点 CvPoint2D32f points_dst[3]; // 边缘点 for (std::size_t i = 0; i < 3; i++){ CvPoint2D32f pt_src_tmp = points_src_rotate[i]; int nearst_id = -1; int nearst_distance = 100000000; for (std::size_t j = 0; j < word_location_point_list.size(); j++){ CvRect rc_tmp; rc_tmp.x = word_location_point_list[j].x*scale_x + 0.55; rc_tmp.y = word_location_point_list[j].y*scale_y + 0.55; rc_tmp.width = word_location_point_list[j].width*scale_x + 0.55; rc_tmp.height = word_location_point_list[j].height*scale_y + 0.55; CvPoint2D32f pt_dst_tmp = cvPoint2D32f(rc_tmp.x + rc_tmp.width / 2.0, rc_tmp.y + rc_tmp.height / 2.0); int distance = get_distance(pt_src_tmp, pt_dst_tmp); if (distance < nearst_distance){ nearst_distance = distance; nearst_id = j; } } if (-1 == nearst_id) return identify::result::IDF_FAILURE; points_dst_[i] = cvPoint2D32f(word_location_point_list[nearst_id].x + word_location_point_list[nearst_id].width / 2.0, word_location_point_list[nearst_id].y + word_location_point_list[nearst_id].height / 2.0);; if (0 == i) points_dst[i] = cvPoint2D32f(word_location_point_list[nearst_id].x, word_location_point_list[nearst_id].y); else if (1 == i) points_dst[i] = cvPoint2D32f(word_location_point_list[nearst_id].x + word_location_point_list[nearst_id].width, word_location_point_list[nearst_id].y); else points_dst[i] = cvPoint2D32f(word_location_point_list[nearst_id].x, word_location_point_list[nearst_id].y + word_location_point_list[nearst_id].height); } #define GET_SCALE 1 #if GET_SCALE int len = 3; int dis_w = get_distance(points_src_rotate[1], points_src_rotate[0]); int dis_h = get_distance(points_src_rotate[0], points_src_rotate[2]); int dis_ww = get_distance(points_dst[1], points_dst[0]); int dis_hw = get_distance(points_dst[0], points_dst[2]); double s_x = dis_w*1.0 / dis_ww*1.0; double s_y = dis_h*1.0 / dis_hw*1.0; int add_left = points_src_rotate[0].x - points_dst[0].x*s_x; int dis_w_right = (word_w - points_dst[1].x)*s_x; int dis_s_right = use_w - points_src_rotate[1].x; int add_right = dis_s_right - dis_w_right; int add_top = points_src_rotate[0].y - points_dst[0].y*s_y; int dis_w_bottom = (word_h - points_dst[1].y)*s_y; int dis_s_bottom = use_h - points_src_rotate[1].y; int add_bottom = dis_s_bottom - dis_w_bottom; IplImage* lp_after_warp = NULL; int xn_w = use_w - add_left - add_right; int xn_h = use_h - add_bottom - add_top; CvRect rc_box;//= cvRect(add_left,add_top,src0->width-add_left-add_right,src0->height-add_top-add_bottom); // 旋转矩形 // 新的水平坐标点更新回 切割后的原图 points_src_[0] = cvPoint2D32f(points_src_rotate[0].x - add_left, points_src_rotate[0].y - add_top); points_src_[1] = cvPoint2D32f(points_src_rotate[1].x - add_left, points_src_rotate[1].y - add_top); points_src_[2] = cvPoint2D32f(points_src_rotate[2].x - add_left, points_src_rotate[2].y - add_top); angle = 0.0; if (0 == dir) { rc_box = cvRect(add_left, add_top, src0->width - add_left - add_right, src0->height - add_top - add_bottom); lp_after_warp = cvCreateImage(cvSize(rc_box.width, rc_box.height), src0->depth, src0->nChannels); dst_img = cvCreateImage(cvSize(lp_after_warp->width, lp_after_warp->height), lp_after_warp->depth, lp_after_warp->nChannels); } else if (1 == dir){ angle = -180; rc_box = cvRect(add_right, add_bottom, src0->width - add_left - add_right, src0->height - add_top - add_bottom); lp_after_warp = cvCreateImage(cvSize(rc_box.width, rc_box.height), src0->depth, src0->nChannels); dst_img = cvCreateImage(cvSize(lp_after_warp->width, lp_after_warp->height), lp_after_warp->depth, lp_after_warp->nChannels); } else if (2 == dir) { angle = -90; rc_box = cvRect(add_top, add_right, src0->width - add_top - add_bottom, src0->height - add_right - add_left); lp_after_warp = cvCreateImage(cvSize(rc_box.width, rc_box.height), src0->depth, src0->nChannels); dst_img = cvCreateImage(cvSize(lp_after_warp->height, lp_after_warp->width), lp_after_warp->depth, lp_after_warp->nChannels); } else if (3 == dir) { angle = -270; rc_box = cvRect(add_bottom, add_left, src0->width - add_bottom - add_top, src0->height - add_left - add_right); lp_after_warp = cvCreateImage(cvSize(rc_box.width, rc_box.height), src0->depth, src0->nChannels); dst_img = cvCreateImage(cvSize(lp_after_warp->height, lp_after_warp->width), lp_after_warp->depth, lp_after_warp->nChannels); } else return identify::result::IDF_FAILURE; if (angle < -1.0){ for (int i = 0; i < 3; i++){ points_src_[i] = get_new_point(points_src_[i], xn_w, xn_h, angle); } } cvSetImageROI(src0, rc_box); cvCopy(src0, lp_after_warp, NULL); #if _DEBUG cvSaveImage("D:\\show\\0.png", lp_after_warp); #endif cvResetImageROI(src0); //} use_w = lp_after_warp->width; use_h = lp_after_warp->height; if (dir > 1) swap(use_h, use_w); double d_x = use_w*1.0 / word_w; double d_y = use_h*1.0 / word_h; points_dst_[0] = cvPoint2D32f(points_dst_[0].x*d_x + 0.55, points_dst_[0].y*d_y + 0.55); points_dst_[1] = cvPoint2D32f(points_dst_[1].x*d_x + 0.55, points_dst_[1].y*d_y + 0.55); points_dst_[2] = cvPoint2D32f(points_dst_[2].x*d_x + 0.55, points_dst_[2].y*d_y + 0.55); #endif CvMat * warp_mat = cvCreateMat(2, 3, CV_32FC1); cvGetAffineTransform(points_src_, points_dst_, warp_mat); cvWarpAffine(lp_after_warp, dst_img, warp_mat, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvScalarAll(255)); cvReleaseMat(&warp_mat); cvReleaseImage(&lp_after_warp); #if _DEBUG cvSaveImage("D:\\show\\1.png", src0); cvSaveImage("D:\\show\\2.png", dst_img); #endif return identify::result::IDF_SUCCESS; } int COnLineCardPageIdentifier::MyFindDingWeiDian(IplImage * src_gray_img, CvMemStorage* storage, schema_const_param &schema_param, vector& locate_point_list, int & _dir) { CvRect roi[4] = {//上下左右 roi cvRect(0, 0, src_gray_img->width, min(300, src_gray_img->height)), cvRect(0, src_gray_img->height - min(300, src_gray_img->height) - 1, src_gray_img->width, min(300, src_gray_img->height)), cvRect(0, 0, min(200, src_gray_img->width), src_gray_img->height), cvRect(src_gray_img->width - min(300, src_gray_img->width) - 1, 0, min(300, src_gray_img->width), src_gray_img->height) }; CvSeq * contour = NULL; for (int dir = 0; dir < 4; dir++) { if (dir < 2)myscale_shema_param0(m_default_schema_param, schema_param, src_gray_img->width / (double)m_default_schema_param.shijuanwidth); else myscale_shema_param0(m_default_schema_param, schema_param, src_gray_img->height / (double)m_default_schema_param.shijuanwidth); IplImage * binary_img = cvCreateImage(cvSize(roi[dir].width + 10, roi[dir].height + 10), IPL_DEPTH_8U, 1); IplImage * binary_img2 = cvCreateImage(cvSize(roi[dir].width + 10, roi[dir].height + 10), IPL_DEPTH_8U, 1); cvSet(binary_img, cvScalarAll(0)); cvSetImageROI(src_gray_img, roi[dir]); cvSetImageROI(binary_img, cvRect(5, 5, roi[dir].width, roi[dir].height)); cvThreshold(src_gray_img, binary_img, 180, 255, CV_THRESH_BINARY_INV); cvResetImageROI(binary_img); int an = 2; IplConvKernel * element = cvCreateStructuringElementEx(an * 2 + 1, an * 2 + 1, an, an, CV_SHAPE_RECT, 0);//创建结构元素 cvErode(binary_img, binary_img2, element, 1);//腐蚀图像 cvDilate(binary_img2, binary_img2, element, 1);//膨胀图像 cvSub(binary_img, binary_img2, binary_img2); cvDilate(binary_img, binary_img, element, 1);//膨胀图像 cvErode(binary_img, binary_img, element, 1);//腐蚀图像 cvSub(binary_img, binary_img2, binary_img); if (element) cvReleaseStructuringElement(&element); #ifdef _DEBUG cvSaveImage("D:\\Debug.jpg",binary_img); #endif int contours = cvFindContours(binary_img, storage, &contour, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cvPoint(roi[dir].x - 5, roi[dir].y - 5)); cvReleaseImage(&binary_img); cvReleaseImage(&binary_img2); int validCount = 0; vector contourList; for (CvContour * c = (CvContour *)contour; c != 0; c = (CvContour *)c->h_next) { locate_point_list.clear(); if (c->rect.width > schema_param.maxw[dir])continue; if (c->rect.height > schema_param.maxh[dir])continue; if (c->rect.width < schema_param.minw[dir] * 0.7)continue; if (c->rect.height < schema_param.minh[dir] * 0.7)continue; cvSetImageROI(src_gray_img, c->rect); int area = GetBlackArea(src_gray_img); if (area < c->rect.width*c->rect.height*0.75)continue; validCount++; contourList.push_back(c); } cvResetImageROI(src_gray_img); std::vector list; for (int i = 0; i < contourList.size(); i++) { CvRect rect = contourList[i]->rect; list.push_back(rect); } CvRect rect; float k = 0, b = 0; if (dir == 0 || dir == 1){ std::sort(list.begin(), list.end(), sort_locate_point_by_x); } else { std::sort(list.begin(), list.end(), sort_locate_point_by_y); } if (list.size() > 1) { bool bV = false; locate_point_list.push_back(list[0]); if (list[list.size() - 1].x - list[0].x>-0.00001 && list[list.size() - 1].x - list[0].x<0.00001) { bV = true; } else{ k = (list[list.size() - 1].y - list[0].y + 0.0) / (list[list.size() - 1].x - list[0].x); } b = list[0].y - k*list[0].x; for (int i = 1; i < list.size() - 1; i++) { if (dir == 0 || dir == 1){ int y = k*list[i].x + b; if (fabs(y - list[i].y + 0.0) < list[i].height / 2) locate_point_list.push_back(list[i]); } else { int x = 0; if (bV){ x = list[0].x; } else{ x =(list[i].y - b) / k; } if (fabs(x - list[i].x + 0.0) < list[i].width / 2) locate_point_list.push_back(list[i]); } } locate_point_list.push_back(list[list.size() - 1]); } if (locate_point_list.size() == 3) { _dir = dir; if (MyFindBottomDingWeiDian(src_gray_img, storage, schema_param, locate_point_list, dir) == identify::result::IDF_FAILURE) return identify::result::IDF_FAILURE; return identify::result::IDF_SUCCESS; break; } } return identify::result::IDF_FAILURE; } //查找定位点 int COnLineCardPageIdentifier::MyFindBottomDingWeiDian(IplImage * src_gray_img, CvMemStorage* storage, schema_const_param &schema_param, vector& locate_point_list, int & _dir) { CvRect roi[4] = {//上下左右 roi cvRect(0, 0, src_gray_img->width, min(300, src_gray_img->height)), cvRect(0, src_gray_img->height - min(300, src_gray_img->height) - 1, src_gray_img->width, min(300, src_gray_img->height)), cvRect(0, 0, min(300, src_gray_img->width), src_gray_img->height), cvRect(src_gray_img->width - min(300, src_gray_img->width) - 1, 0, min(300, src_gray_img->width), src_gray_img->height) }; CvSeq * contour = NULL; int dir; _dir > 1 ? dir = 3 - _dir + 2 : dir = 1 - _dir; m_vecBottom.clear(); //for (int dir=0;dir<4;dir++) { IplImage * binary_img = cvCreateImage(cvSize(roi[dir].width + 10, roi[dir].height + 10), IPL_DEPTH_8U, 1); IplImage * binary_img2 = cvCreateImage(cvSize(roi[dir].width + 10, roi[dir].height + 10), IPL_DEPTH_8U, 1); cvSet(binary_img, cvScalarAll(0)); cvSetImageROI(src_gray_img, roi[dir]); cvSetImageROI(binary_img, cvRect(5, 5, roi[dir].width, roi[dir].height)); cvThreshold(src_gray_img, binary_img, 180, 255, CV_THRESH_BINARY_INV); cvResetImageROI(binary_img); int an = 2; IplConvKernel * element = cvCreateStructuringElementEx(an * 2 + 1, an * 2 + 1, an, an, CV_SHAPE_RECT, 0);//创建结构元素 cvErode(binary_img, binary_img2, element, 1);//腐蚀图像 cvDilate(binary_img2, binary_img2, element, 1);//膨胀图像 cvSub(binary_img, binary_img2, binary_img2); cvDilate(binary_img, binary_img, element, 1);//膨胀图像 cvErode(binary_img, binary_img, element, 1);//腐蚀图像 cvSub(binary_img, binary_img2, binary_img); int contours = cvFindContours(binary_img, storage, &contour, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cvPoint(roi[dir].x - 5, roi[dir].y - 5)); if (element) cvReleaseStructuringElement(&element); cvReleaseImage(&binary_img); cvReleaseImage(&binary_img2); int validCount = 0; vector contourList; for (CvContour * c = (CvContour *)contour; c != 0; c = (CvContour *)c->h_next) { if (c->rect.width > schema_param.maxw[dir])continue; if (c->rect.height > schema_param.maxh[dir])continue; if (c->rect.width < schema_param.minw[dir] * 0.7)continue; if (c->rect.height < schema_param.minh[dir] * 0.7)continue; cvSetImageROI(src_gray_img, c->rect); //cvSaveImage( "d://debug1.jpg", binary_img ); int area = GetBlackArea(src_gray_img); if (area < c->rect.width*c->rect.height*0.75)continue; validCount++; contourList.push_back(c); } cvResetImageROI(src_gray_img); if (contourList.size() == 2){ for (std::size_t i = 0; i < contourList.size(); i++){ CvRect rect = contourList[i]->rect; m_vecBottom.push_back(rect); } if (m_vecBottom.size() > 1){ std::sort(m_vecBottom.begin(), m_vecBottom.end(), sort_locate_point_by_x); if (_dir == 1) std::sort(m_vecBottom.begin(), m_vecBottom.end(), sort_locate_point_by_x); } return identify::result::IDF_SUCCESS; } else { return identify::result::IDF_FAILURE; } } } int COnLineCardPageIdentifier::OnLineCardJZ(IplImage* src, IplImage* &dst_img, int nPageIndex, int dir, std::vector&main_locate_point, int &wordloctlt) { int ret = identify::result::IDF_FAILURE; std::vector vec_locations_word; vec_locations_word.clear(); double tt[4] = { 0.0, 0.0, 0.0, 0.0 }; if (!m_pTemplate->pages.empty()){ PageTemplate&page = m_pTemplate->pages[nPageIndex]; std::vector& lcs = page.location; for (std::size_t j = 0; j < lcs.size(); j++){ CvRect rc_tmp; rc_tmp.x = lcs[j].pos.x; rc_tmp.y = lcs[j].pos.y; rc_tmp.width = lcs[j].pos.w; rc_tmp.height = lcs[j].pos.h; vec_locations_word.push_back(rc_tmp); } wordloctlt = vec_locations_word[3].y - vec_locations_word[0].y; double word_w = page.w; double word_h = page.h; tt[2] = word_w; tt[3] = word_h; // resize point int mb_w = src->width; int mb_h = src->height; if (2 == dir || 3 == dir) // swap(mb_h, mb_w); float rio_w = mb_w*1.0 / word_w*1.0; float rio_h = mb_h*1.0 / word_h*1.0; tt[0] = rio_w; tt[1] = rio_h; for (std::size_t i = 0; i < vec_locations_word.size(); i++){ vec_locations_word[i].x = vec_locations_word[i].x*rio_w + 0.55; vec_locations_word[i].y = vec_locations_word[i].y*rio_h + 0.55; vec_locations_word[i].width = vec_locations_word[i].width*rio_w + 0.55; vec_locations_word[i].height = vec_locations_word[i].height*rio_h + 0.55; } } if (2 == m_vecBottom.size() && vec_locations_word.size()>3){ try{ // 三点校正 ret = JiaoZheng_20200418_first(src, dst_img, main_locate_point, m_vecBottom, vec_locations_word, dir); } catch (cv::Exception &e) { return identify::result::IDF_FAILURE; } } return ret; } void COnLineCardPageIdentifier::InitScoreArea(SchemaQuestionScore&sqs, const ScoreBox&box, CvPoint offset, double w_scale, double h_scale) { // 打分框类型 sqs.scoreBox.type = box.type; // 填空题打分类型 sqs.scoreBox.vctScore = box.vctScore; // 上限 sqs.scoreBox.limit = box.limit; // 最后一个格子是否为小数(0.5分) sqs.scoreBox.bPoint = box.bPoint; // 位置 sqs.scoreBox.pos.x = offset.x + box.pos.x * w_scale; sqs.scoreBox.pos.y = offset.y + box.pos.y * h_scale; sqs.scoreBox.pos.w = box.pos.w *w_scale; sqs.scoreBox.pos.h = box.pos.h *h_scale; } int COnLineCardPageIdentifier::GetQrCode(IplImage* dst_gray_img, schema_const_param &schema_param, vector &main_locate_point, vector &codev, string& paper_id, string& student_code) { std::string result; CvRect myRect = cvRect(max(0, min(dst_gray_img->width - schema_param.paper_bar_width1, main_locate_point[0].x + schema_param.paper_bar_offsetx1)), max(0, min(dst_gray_img->height - schema_param.paper_bar_height1, main_locate_point[0].y + schema_param.paper_bar_offsety1)), schema_param.paper_bar_width1, schema_param.paper_bar_height1); IplImage* mydst_gray_img = NULL; xuanzhuan(dst_gray_img, mydst_gray_img, myRect); #ifdef _DEBUG cv::imwrite("D:\\TTTTT.JPG", cvarrToMat(mydst_gray_img)); #endif cv::Mat matDstGray = cvarrToMat(mydst_gray_img); int ret = 0; try{ ret = GetQR(matDstGray, result); } catch (cv::Exception&e){ const char* what = e.what(); int n = 0; ++n; } //CParseQRInfo test; //char result[512] = { 0 }; //bool bRet = test.parseQRInfo(matDstGray, result, sizeof(result)/sizeof(char)); //if (/*ret == identify::result::IDF_SUCCESS*/bRet){ if (ret == identify::result::IDF_SUCCESS){ SchemaCode qrcode1; qrcode1.centerx = (main_locate_point[0].x + schema_param.paper_bar_offsetx1) + schema_param.paper_bar_width1 / 2.0; qrcode1.centery = (main_locate_point[0].y + schema_param.paper_bar_offsety1) + schema_param.paper_bar_height1 / 2.0; qrcode1.width = schema_param.paper_bar_width1; qrcode1.height = schema_param.paper_bar_height1; qrcode1.index = obj_index++; qrcode1.nQrOrBar = 1; qrcode1.isXuanZhuan = false; student_code = result; qrcode1.strContent = result; codev.push_back(qrcode1); } if (mydst_gray_img != NULL)cvReleaseImage(&mydst_gray_img); return identify::result::IDF_SUCCESS; } void COnLineCardPageIdentifier::CalcPos(const Pos&pos, const CvPoint& offset, double w_scale, double h_scale, int ¢er_x, int ¢er_y, int &w, int &h) { w = static_cast(pos.w*w_scale); h = static_cast(pos.h*h_scale); center_x = static_cast(offset.x + pos.x*w_scale + pos.w*w_scale / 2); center_y = static_cast(offset.y + pos.y*h_scale + pos.h*h_scale / 2); } void COnLineCardPageIdentifier::SetPageDefault(SchemaPage& page) { page.codeCount = 0; page.cutAreaCount = 0; page.group_spacer = ';'; page.groupCount = 0; page.stuItemCount = 0; page.stuGroupsCount = 0; page.hei_du_ling_min_du = 4; page.height = 0; page.index = 0; page.itemCount = 0; page.locateAreaCount = 0; page.locateCrossCount = 0; page.locatePointCount = 0; page.option_spacer = ','; page.question_score_count = 0; page.unselect_char = '*'; page.user_float_heidu = 4; page.width = 0; page.worthwhileBlk = 4; } void COnLineCardPageIdentifier::SetTemplate(OnLineCard::PaperTemplate*pT) { m_pTemplate = pT; int dingweidianH; int dingweidianW; if (m_pTemplate->pages[1].location.size() >= 5){ int m = 0; dingweidianH = m_pTemplate->pages[1].location[m].pos.h; dingweidianW = m_pTemplate->pages[1].location[m].pos.w; m_default_schema_param.main_locate_point_distance = m_pTemplate->pages[1].location[m + 2].pos.x - m_pTemplate->pages[1].location[m].pos.x; m_default_schema_param.shijuanwidth = m_pTemplate->pages[1].w; for (int i = 0; i < 4; i++) { if (i < 2) { m_default_schema_param.minw[i] = dingweidianW*0.75; m_default_schema_param.maxw[i] = dingweidianW*1.25; m_default_schema_param.minh[i] = dingweidianH*0.75; m_default_schema_param.maxh[i] = dingweidianH*1.25; } else { m_default_schema_param.minw[i] = dingweidianH*0.75; m_default_schema_param.maxw[i] = dingweidianH*1.25; m_default_schema_param.minh[i] = dingweidianW*0.75; m_default_schema_param.maxh[i] = dingweidianW*1.25; } } } } int COnLineCardPageIdentifier::createSchema(const IplImage* src, IplImage* *dst, SchemaPage* *pageSchema, const char * result_path, bool flag, std::string qr, bool bUseQr) { if (!m_pTemplate || m_pTemplate->pages.size() < 2 || m_pTemplate->pages[1].location.size() < 5){ return identify::result::IDF_FAILURE; } int wordloctlt = 0; int schoolCardStatus = m_pTemplate->schoolCardStatus; obj_index = 0; CvRect roi_old = cvGetImageROI(src); IplImage * src0 = (IplImage *)src; int ret; int mode_type = 1115; vector groupv; vector itemv; vector scorev; vector codev; vector cutareav; vector questionLocatePoints; vector keguanti_question_locatepoint_indexs; vector stuGroupv; vector stuItemv; vector stuIndex; vector quekaoIndex; CvMemStorage* storage = cvCreateMemStorage(0); IplImage * src_gray_img; int question_count = 0; int itemcount = 0; cvResetImageROI((IplImage*)src0); src_gray_img = cvCreateImage(cvGetSize(src0), IPL_DEPTH_8U, 1); cvCvtColor(src0, src_gray_img, CV_BGR2GRAY); schema_const_param schema_param; std::vector main_locate_point; CvPoint offset_pt; int dir;//上下左右 // printf("线程:%s 第一次查找定位点\n", std::to_string(GetCurrentThreadId()).c_str()); ret = MyFindDingWeiDian(src_gray_img, storage, schema_param, main_locate_point, dir); if (ret != identify::result::IDF_SUCCESS){ cv::Size sz; std::vector vec_locations_word; vec_locations_word.clear(); if (!m_pTemplate->pages.empty()){ PageTemplate&page = m_pTemplate->pages[1]; sz = cv::Size(page.w, page.h); std::vector& lcs = page.location; for (std::size_t j = 0; j < lcs.size(); j++){ cv::Rect rc_tmp; rc_tmp.x = lcs[j].pos.x; rc_tmp.y = lcs[j].pos.y; rc_tmp.width = lcs[j].pos.w; rc_tmp.height = lcs[j].pos.h; vec_locations_word.push_back(rc_tmp); } } std::vector vec_tops; // 接受找到的上面三个定位点 下标访问 std::vector vec_bottoms; // 接受找到的下面的两个定位点 下标访问 std::vector vec_len; vec_tops.resize(100); vec_bottoms.resize(100); vec_len.push_back(-1); vec_len.push_back(-1); #ifdef _DEBUG cv::imwrite("D:\\src_gray_img.png", cv::cvarrToMat(src_gray_img)); #endif int nRet = api_location_anchor_points(cv::cvarrToMat(src_gray_img), vec_locations_word, sz, vec_tops, vec_bottoms, vec_len, dir, 3, 1); if (nRet == 0 && vec_len.size()==2 && vec_len[0] == 3 && vec_len[1] == 2){ main_locate_point.clear(); m_vecBottom.clear(); for (std::size_t i = 0; i < vec_tops.size() && i < vec_len[0]; ++i){ main_locate_point.push_back(vec_tops[i]); } for (std::size_t i = 0; i < vec_bottoms.size() && i < vec_len[1]; ++i){ m_vecBottom.push_back(vec_bottoms[i]); } } else{ cvReleaseMemStorage(&storage); cvReleaseImage(&src_gray_img); cvSetImageROI(src0, roi_old); return identify::result::IDF_TEMPLATE_NOTFOUND_ENOUGH_LOCATEPOINT; } } IplImage * dst_img = NULL; // printf("线程:%s 开始矫正\n", std::to_string(GetCurrentThreadId()).c_str()); ret = OnLineCardJZ(src0, dst_img, 1, dir, main_locate_point, wordloctlt); if (ret != identify::result::IDF_SUCCESS){ cvReleaseMemStorage(&storage); cvReleaseImage(&src_gray_img); cvSetImageROI(src0, roi_old); if (dst_img)cvReleaseImage(&dst_img); return identify::result::IDF_TEMPLATE_NOTFOUND_ENOUGH_LOCATEPOINT; } //printf("线程:%s 矫正结束\n", std::to_string(GetCurrentThreadId()).c_str()); IplImage* dst_gray_img = cvCreateImage(cvGetSize(dst_img), IPL_DEPTH_8U, 1); cvCvtColor(dst_img, dst_gray_img, CV_BGR2GRAY); int locate_point_count = main_locate_point.size(); main_locate_point.clear(); //printf("线程:%s 第二次查找定位点\n", std::to_string(GetCurrentThreadId()).c_str()); ret = MyFindDingWeiDian(dst_gray_img, storage, schema_param, main_locate_point, dir); std::sort(main_locate_point.begin(), main_locate_point.end(), sort_locate_point_by_x); if (ret != identify::result::IDF_SUCCESS || main_locate_point.size() != locate_point_count){ cv::Size sz; std::vector vec_locations_word; vec_locations_word.clear(); if (!m_pTemplate->pages.empty()){ PageTemplate&page = m_pTemplate->pages[1]; sz = cv::Size(page.w, page.h); std::vector& lcs = page.location; for (std::size_t j = 0; j < lcs.size(); j++){ cv::Rect rc_tmp; rc_tmp.x = lcs[j].pos.x; rc_tmp.y = lcs[j].pos.y; rc_tmp.width = lcs[j].pos.w; rc_tmp.height = lcs[j].pos.h; vec_locations_word.push_back(rc_tmp); } } std::vector vec_tops; // 接受找到的上面三个定位点 下标访问 std::vector vec_bottoms; // 接受找到的下面的两个定位点 下标访问 std::vector vec_len; vec_tops.resize(100); vec_bottoms.resize(100); vec_len.push_back(-1); vec_len.push_back(-1); int nRet = api_location_anchor_points(cv::cvarrToMat(src_gray_img), vec_locations_word, sz, vec_tops, vec_bottoms, vec_len, dir, 3, 1); if (nRet == 0 && vec_len.size() == 2 && vec_len[0] == 3 && vec_len[1] == 2){ main_locate_point.clear(); m_vecBottom.clear(); for (std::size_t i = 0; i < vec_tops.size() && i < vec_len[0]; ++i){ main_locate_point.push_back(vec_tops[i]); } for (std::size_t i = 0; i < vec_bottoms.size() && i < vec_len[1]; ++i){ m_vecBottom.push_back(vec_bottoms[i]); } } else{ cvReleaseMemStorage(&storage); cvReleaseImage(&src_gray_img); cvReleaseImage(&dst_gray_img); cvSetImageROI(src0, roi_old); if (dst_img)cvReleaseImage(&dst_img); return identify::result::IDF_TEMPLATE_NOTFOUND_ENOUGH_LOCATEPOINT; } } double fffx = (main_locate_point[main_locate_point.size() - 1].x - main_locate_point[0].x)*(main_locate_point[main_locate_point.size() - 1].x - main_locate_point[0].x); double fffy = (main_locate_point[main_locate_point.size() - 1].y - main_locate_point[0].y)*(main_locate_point[main_locate_point.size() - 1].y - main_locate_point[0].y); double w_scale = (sqrt(fffx + fffy)) / m_default_schema_param.main_locate_point_distance; double Hfffx = (m_vecBottom[0].x - main_locate_point[0].x)*(m_vecBottom[0].x - main_locate_point[0].x); double Hfffy = (m_vecBottom[0].y - main_locate_point[0].y)*(m_vecBottom[0].y - main_locate_point[0].y); double h_scale = (sqrt(Hfffx + Hfffy)) / wordloctlt; { //保存 SchemaLocatePoint leftp; leftp.centerx = main_locate_point[0].x + main_locate_point[0].width / 2.0; leftp.centery = main_locate_point[0].y + main_locate_point[0].height / 2.0; leftp.width = main_locate_point[0].width; leftp.height = main_locate_point[0].height; questionLocatePoints.push_back(leftp); SchemaLocatePoint rightp; rightp.centerx = main_locate_point[2].x + main_locate_point[2].width / 2.0; rightp.centery = main_locate_point[2].y + main_locate_point[2].height / 2.0; rightp.width = main_locate_point[2].width; rightp.height = main_locate_point[2].height; questionLocatePoints.push_back(rightp); leftp.centerx = m_vecBottom[0].x + m_vecBottom[0].width / 2.0; leftp.centery = m_vecBottom[0].y + m_vecBottom[0].height / 2.0; leftp.width = m_vecBottom[0].width; leftp.height = m_vecBottom[0].height; questionLocatePoints.push_back(leftp); rightp.centerx = m_vecBottom[1].x + m_vecBottom[1].width / 2.0; rightp.centery = m_vecBottom[1].y + m_vecBottom[1].height / 2.0; rightp.width = m_vecBottom[1].width; rightp.height = m_vecBottom[1].height; questionLocatePoints.push_back(rightp); } int page_index = 1; string paper_id = ""; string student_code = ""; bool is_stu_id = false; offset_pt.x = main_locate_point[0].x; offset_pt.y = main_locate_point[0].y; bool front_page = false; //判断前后页 if ((main_locate_point[1].x - main_locate_point[0].x) < (main_locate_point[2].x - main_locate_point[1].x)){//正面 front_page = true; } else{ front_page = false; } PageTemplate&page = m_pTemplate->pages[front_page ? 1 : 2]; // 正面 if (front_page){ SchemaCode code_tmp; std::vector split_qr; split(qr, (std::string)",", &split_qr); if (split_qr.size() > 0){ if (split_qr.size() > 0) paper_id = split_qr[0]; if (bUseQr){ if (split_qr.size() > 2){ std::vector _vct; split(split_qr[2], std::string("@"), &_vct); if (_vct.size() > 1){ student_code = _vct[2]; is_stu_id = !student_code.empty(); } } } } if (bUseQr&&!student_code.empty()) { SchemaCode code; code.index = obj_index++; code.nQrOrBar = 1; code.strContent = paper_id + "_" + student_code + "_3_1"; codev.push_back(code); } else{ // 二维码 schema_param.paper_bar_width1 = page.QrCode.w*w_scale; schema_param.paper_bar_height1 = page.QrCode.h*h_scale; schema_param.paper_bar_offsetx1 = page.QrCode.x*w_scale; schema_param.paper_bar_offsety1 = page.QrCode.y*h_scale; if (m_pTemplate->useQrCode){ std::size_t nOld = codev.size(); ret = GetQrCode(dst_gray_img, schema_param, main_locate_point, codev, paper_id, student_code); if (ret != identify::result::IDF_SUCCESS){ cvReleaseMemStorage(&storage); cvReleaseImage(&src_gray_img); cvReleaseImage(&dst_img); cvReleaseImage(&dst_gray_img); return identify::result::IDF_TEMPLATE_QRCODE_ILLEGAL; } if (nOld < codev.size()){ vector splits; split(student_code, (std::string)"@", &splits); if (splits.size() == 1){ paper_id = splits[0]; codev[codev.size() - 1].strContent = paper_id + "_6582234412574771625_3_1_12_1_1_1"; student_code = ""; } else if (splits.size() >= 2){ student_code = splits[0]; paper_id = splits[1]; codev[codev.size() - 1].strContent = paper_id + "_" + student_code + "_3_1"; } if (student_code.empty()){ if (!codev.empty()) code_tmp = codev[0]; codev.clear(); } } is_stu_id = !student_code.empty(); } // 二维码中含有学生信息 不需要识别条形码和填涂考号 if (!m_pTemplate->useQrCode) { //条形码 schema_param.paper_bar_width1 = page.studentcode_bar.w*w_scale; schema_param.paper_bar_height1 = page.studentcode_bar.h*h_scale; schema_param.paper_bar_offsetx1 = page.studentcode_bar.x*w_scale; schema_param.paper_bar_offsety1 = page.studentcode_bar.y*h_scale; if (schema_param.paper_bar_width1 != 0 && schema_param.paper_bar_height1 != 0){ auto oldSize = codev.size(); ret = GetQrCode(dst_gray_img, schema_param, main_locate_point, codev, paper_id, student_code); if (ret != identify::result::IDF_SUCCESS){ cvReleaseMemStorage(&storage); cvReleaseImage(&src_gray_img); cvReleaseImage(&dst_img); cvReleaseImage(&dst_gray_img); return identify::result::IDF_TEMPLATE_QRCODE_ILLEGAL;; } if (oldSize < codev.size()){ codev[codev.size() - 1].strContent = paper_id + "_" + student_code + "_3_1_12_1_1_1"; } } //填涂考号 if (student_code.empty()) { int q_item_count = 10; int itemcount = 0; int question_count = 0; int x, y, w, h; for (std::size_t j = 0; j < page.studentcode_fill.size(); j++) { SchemaGroup group; group.question_code = ""; group.index = question_count++; group.question_index = question_count; group.itemCount = q_item_count; group.itemIndex.clear(); group.omr_out_type = OMR_OUT_TYPE::OMR_OUT_TYPE_SINGLE_NONSTRICT; for (std::size_t m = 0; m < page.studentcode_fill[j].size(); m++) { group.itemIndex.push_back(itemcount + m); SchemaItem item; CalcPos(page.studentcode_fill[j][m].pos, offset_pt, w_scale, h_scale, item.centerx, item.centery, item.width, item.height); std::string&optName = page.studentcode_fill[j][m].optName; if (!optName.empty()) item.OutChar = std::stoi(optName) + '0'; item.keguanti_question_locate_point_index = stuIndex.size(); stuItemv.push_back(item); } if (j == 0){ x = stuItemv[0].centerx - stuItemv[0].width / 2 - 35; y = stuItemv[0].centery - stuItemv[0].height - stuItemv[0].height / 2 - 105; } else if (j == page.studentcode_fill.size() - 1){ SchemaItem &item = stuItemv[stuItemv.size() - 1]; int tx = item.centerx + item.width / 2 + 35; int ty = item.centery + item.height / 2 + 5; w = tx - x; h = ty - y; } itemcount += q_item_count; stuGroupv.push_back(group); } KEGUANTI_QUESTION_LOCATEPOINT_INDEX kqli; kqli[0] = 0; kqli[1] = 1; kqli[2] = 2; kqli[3] = 3; stuIndex.push_back(kqli); code_tmp.centerx = x + w / 2; code_tmp.centery = y + h / 2; code_tmp.width = w; code_tmp.height = h; code_tmp.index = obj_index++; code_tmp.nQrOrBar = 1; code_tmp.strContent = paper_id + "_6582234412574771625_3_1_12_1_1_1"; codev.clear(); codev.push_back(code_tmp); } } } // 缺考标记 { schema_param.quekao_item_offset_x = main_locate_point[0].x + page.absent.x*w_scale; schema_param.quekao_item_offset_y = main_locate_point[0].y + page.absent.y*h_scale; schema_param.quekao_item_width = page.absent.w*w_scale; schema_param.quekao_item_height = page.absent.h*h_scale; KEGUANTI_QUESTION_LOCATEPOINT_INDEX QKIndex; QKIndex[0] = 0; QKIndex[1] = 1; QKIndex[2] = 2; QKIndex[3] = 3; quekaoIndex.push_back(QKIndex); } } for (std::size_t i = 0; i < page.vctQuestions.size(); ++i){ question&qt = page.vctQuestions[i]; if (qt.type == 0 || qt.type == 8){//选 SchemaGroup group; question_count++; group.question_code = qt.id; static int id = 0; id = std::stoi(qt.id); group.index = obj_index++; group.question_index = question_count; group.itemCount = qt.opt.size(); group.itemIndex.clear(); group.omr_out_type = qt.type == 0 ? OMR_OUT_TYPE::OMR_OUT_TYPE_SINGLE_NONSTRICT : OMR_OUT_TYPE::OMR_OUT_TYPE_MUTIL_STRICT; for (int q = 0; q < group.itemCount; q++) { group.itemIndex.push_back(itemcount + q); SchemaItem item; CalcPos(qt.opt[q].pos, offset_pt, w_scale, h_scale, item.centerx, item.centery, item.width, item.height); if (!qt.opt[q].optName.empty()) item.OutChar = qt.opt[q].optName.at(0); item.keguanti_question_locate_point_index = keguanti_question_locatepoint_indexs.size(); itemv.push_back(item); } itemcount += group.itemCount; groupv.push_back(group); KEGUANTI_QUESTION_LOCATEPOINT_INDEX kqli; kqli[0] = 0; kqli[1] = 1; kqli[2] = 2; kqli[3] = 3; keguanti_question_locatepoint_indexs.push_back(kqli); } else if (qt.type == 1 || qt.type == 2){ //通过linkparm判断第一次还是第二次出现(第一次一定小于2) if (qt.cut.linkparm < 2){ SchemaQuestionScore sqs; cv::warpAffine; sqs.type = QUESTION_SCORE_TYPE::MUTIL_SCORE; InitScoreArea(sqs, qt.scoreBox, offset_pt, w_scale, h_scale); if (sqs.scoreBox.type == 1){ // 1-16 sqs.count = sqs.scoreBox.limit; if (sqs.scoreBox.bPoint) sqs.count++; } else if (sqs.scoreBox.type == 2){ // 29/49 sqs.count = ((int)sqs.scoreBox.limit / 10) + 12;// 12 = 各位数字+ 十/个位标记 10+2 if (sqs.scoreBox.bPoint) sqs.count++; } sqs.scoreBox.bXuanZuoTi = (qt.type == 2); sqs.index = obj_index++; if (!qt.id.empty()) sqs.question_index = std::stoi(qt.id); sqs.question_code = qt.id; if (qt.type ==2){ sqs.question_code_all = qt.all_id; } sqs.valid_option_count = 0; sqs.questionLocatePointIndex[0] = 0; sqs.questionLocatePointIndex[1] = 1; CalcPos(qt.cut.pos, offset_pt, w_scale, h_scale, sqs.centerx, sqs.centery, sqs.width, sqs.height); if (qt.type == 2){ sqs.questionLocatePointIndex[2] = 2; sqs.questionLocatePointIndex[3] = 3; for (int v = 0; v < qt.selTotal && qt.opt.size() == qt.selTotal; v++) { CalcPos(qt.opt[v].pos, offset_pt, w_scale, h_scale, sqs.item[v].centerx, sqs.item[v].centery, sqs.item[v].width, sqs.item[v].height); } sqs.countItemSelete = qt.selItem; sqs.countNum = qt.selTotal; SetTBLR(sqs); } SchemaCutArea cutarea; cutarea.index = obj_index++; cutarea.area_name = sqs.question_code; cutarea.isfirst = TRUE; cutarea.question_index = sqs.question_index; cutarea.iscut = TRUE; CalcPos(qt.cut.pos, offset_pt, w_scale, h_scale, cutarea.centerx, cutarea.centery, cutarea.width, cutarea.height); SetTBLR(sqs); scorev.push_back(sqs); cutareav.push_back(cutarea); }else{ SchemaCutArea cutarea; CalcPos(qt.cut.pos, offset_pt, w_scale, h_scale, cutarea.centerx, cutarea.centery, cutarea.width, cutarea.height); cutarea.index = obj_index++; cutarea.isfirst = FALSE; cutarea.question_index = -1; cutarea.area_name = qt.id; cutareav.push_back(cutarea); } }else if (qt.type == 3){ //填空(不会跨页,所以可以直接处理) SchemaQuestionScore sqs; sqs.type = QUESTION_SCORE_TYPE::SINGLE_SCORE; InitScoreArea(sqs, qt.scoreBox, offset_pt, w_scale, h_scale); sqs.count = sqs.scoreBox.vctScore.size(); if (sqs.count <= 0) sqs.count = 1; sqs.index = obj_index++; if (!qt.id.empty()) sqs.question_index = std::stoi(qt.id); sqs.question_code = qt.id; sqs.valid_option_count = 0; sqs.questionLocatePointIndex[0] = 0; sqs.questionLocatePointIndex[1] = 1; CalcPos(qt.cut.pos, offset_pt, w_scale, h_scale, sqs.centerx, sqs.centery, sqs.width, sqs.height); SchemaCutArea cutarea; cutarea.index = obj_index++; cutarea.area_name = sqs.question_code; cutarea.isfirst = TRUE; cutarea.question_index = question_count; cutarea.iscut = FALSE; CalcPos(qt.cut.pos, offset_pt, w_scale, h_scale, cutarea.centerx, cutarea.centery, cutarea.width, cutarea.height); SetTBLR(sqs); scorev.push_back(sqs); cutareav.push_back(cutarea); } } SchemaPage* schemapage = (SchemaPage*) new SchemaPage; SetPageDefault(*schemapage); schemapage->schoolCardStatus = m_pTemplate->schoolCardStatus; schemapage->isZaiXianDaTiKa = true; schemapage->index = front_page ? page_index : 2; strcpy(schemapage->paper_id, paper_id.c_str()); strcpy(schemapage->student_code, student_code.c_str()); schemapage->is_stu_id = is_stu_id; schemapage->width = dst_img->width; schemapage->height = dst_img->height; schemapage->locatePointCount = main_locate_point.size(); schemapage->questionLocatePoints = questionLocatePoints; schemapage->keguantiQuestionLocatePointIndexs = keguanti_question_locatepoint_indexs; schemapage->stuQuestionLocatePointIndex = stuIndex; schemapage->codeCount = codev.size(); schemapage->groupCount = groupv.size(); schemapage->itemCount = itemv.size(); schemapage->stuGroupsCount = stuGroupv.size(); schemapage->stuItemCount = stuItemv.size(); schemapage->question_score_count = scorev.size(); schemapage->cutAreaCount = cutareav.size(); int offset = sizeof(SchemaPage); for (std::size_t i = 0; i < main_locate_point.size(); i++) { SchemaLocatePoint slp; slp.centerx = main_locate_point[i].x + main_locate_point[i].width / 2.; slp.centery = main_locate_point[i].y + main_locate_point[i].height / 2.; slp.width = main_locate_point[i].width; slp.height = main_locate_point[i].height; schemapage->locatePoints.push_back(slp); } schemapage->codes = codev; schemapage->groups = groupv; schemapage->items = itemv; schemapage->question_score = scorev; schemapage->cutAreas = cutareav; schemapage->mode_type = mode_type; schemapage->stuGroups = stuGroupv; schemapage->stuItems = stuItemv; schemapage->schoolCardStatus = schoolCardStatus; //缺考标记相关参数 schemapage->quekao.centerx = schema_param.quekao_item_offset_x + schema_param.quekao_item_width / 2; schemapage->quekao.centery = schema_param.quekao_item_offset_y + schema_param.quekao_item_height / 2; schemapage->quekao.width = schema_param.quekao_item_width; schemapage->quekao.height = schema_param.quekao_item_height; schemapage->quekaoLocatePointIndex = quekaoIndex; *pageSchema = schemapage; if (flag){ DrawSchema(dst_img, schemapage); cvSaveImage(result_path, dst_img); } cvReleaseMemStorage(&storage); cvReleaseImage(&src_gray_img); *dst = dst_img; cvReleaseImage(&dst_gray_img); { cvSetImageROI(src0, roi_old); return identify::result::IDF_SUCCESS; } //printf("线程:%s 单页识别结束\n", std::to_string(GetCurrentThreadId()).c_str()); } std::string getTimeStamp() { std::chrono::time_point tp = std::chrono::time_point_cast(std::chrono::system_clock::now()); auto tmp = std::chrono::duration_cast(tp.time_since_epoch()); std::time_t timestamp = tmp.count(); return std::move(std::to_string(timestamp)); } //按照指定模板进行识别 int COnLineCardPageIdentifier::Identify_impl() { int ret = BaseCheck(); if (ret != identify::result::IDF_SUCCESS)return ret; InitalizeTempVar(); CvMemStorage* storage = cvCreateMemStorage(0); IplImage * dst = NULL; SchemaPage* pschemaPage = NULL; std::string path = std::string("d:\\image\\") + getTimeStamp() + ".jpg"; ret = createSchema(src, &dst, &pschemaPage, path.c_str(), true, m_strQrClass, m_bUseQr); if (ret != identify::result::IDF_SUCCESS){ if (dst != NULL)cvReleaseImage(&dst); cvReleaseMemStorage(&storage); return ret; } SchemaPage& schemaPage = *pschemaPage; /************************读取学生学号*********************************************/ ret = ReadStudentID(schemaPage, dst); if (ret != identify::result::IDF_SUCCESS) { if (dst != NULL)cvReleaseImage(&dst); cvReleaseMemStorage(&storage); if (pschemaPage != NULL)delete pschemaPage; return ret; } /************************查找题目定位点,准备定位数据*********************************************/ ret = FindQuestionLocatePoints(schemaPage, dst); if (ret != identify::result::IDF_SUCCESS) { if (dst != NULL)cvReleaseImage(&dst); cvReleaseMemStorage(&storage); if (pschemaPage != NULL)delete pschemaPage; return ret; } /************************客观题()*********************************************/ ret = ReadKeGuanTi(schemaPage, dst); if (ret != identify::result::IDF_SUCCESS) { if (dst != NULL)cvReleaseImage(&dst); cvReleaseMemStorage(&storage); if (pschemaPage != NULL)delete pschemaPage; return ret; } /************************阅卷读取*************************************************/ ret = ReadQuestionScore(schemaPage, dst, storage); if (ret != identify::result::IDF_SUCCESS) { if (dst != NULL)cvReleaseImage(&dst); cvReleaseMemStorage(&storage); if (pschemaPage != NULL)delete pschemaPage; return ret; } /************************根据给定区域切割图片*********************************************/ ret = ClipImg(schemaPage, dst); if (ret != identify::result::IDF_SUCCESS) { if (dst != NULL)cvReleaseImage(&dst); cvReleaseMemStorage(&storage); if (pschemaPage != NULL)delete pschemaPage; return ret; } /************************读取缺考标记*********************************************/ omr_result->quekaoFlag = ReadQuekaoFlag(schemaPage, dst); omr_result->card_index = schemaPage.index; if (dst != NULL)cvReleaseImage(&dst); cvReleaseMemStorage(&storage); if (pschemaPage != NULL)delete pschemaPage; return identify::result::IDF_SUCCESS; } //获取全局背景灰度,通过统计所有涂点周围像素(灰度不小于160)的灰度平均值获得 int COnLineCardPageIdentifier::caculate_global_background(SchemaPage& schemaPage, IplImage * dst, bool flag) { int global_background_color_count = 0; int global_background_color_avg = 0; int totalCount = 0; if (!flag) { totalCount = schemaPage.itemCount; } else { totalCount = schemaPage.stuItemCount; } for (int i = 0; inChannels == 1)GetGray = GetGrayValue; else GetGray = GetBGRGray; for (int x = left; x <= right; x++) { gray = GetGray(dst, x, vtop); if (gray>160){ background_color_avg += gray; background_color_count++; } gray = GetGray(dst, x, vbottom); if (gray>160){ background_color_avg += gray; background_color_count++; } } background_color_avg = background_color_count>0 ? background_color_avg / background_color_count : 0; if (background_color_avg>100){ global_background_color_avg += background_color_avg; global_background_color_count++; } } global_background_color_avg = global_background_color_count>0 ? global_background_color_avg / global_background_color_count : 0; return global_background_color_avg; } //计算涂点属性 inline int COnLineCardPageIdentifier::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) { int gray;//临时变量,灰度值 //int tembackcolor=max((anlyseResult.globalBackGround+200)/2,200); int tembackcolor = (flag == 0) ? max(anlyseResult.backGroundGray - 20, 200) : max(anlyseResult.backGroundGray - 20, 0); //获取灰度的函数指针 int(*ggray)(const IplImage * dst, int x, int y); if (dst->nChannels == 1)ggray = GetGrayValue; else ggray = GetBGRGray; int left = int(item.centerx - item.width / 2. + 0.5); int top = int(item.centery - item.height / 2. + 0.5); int right = int(item.centerx + item.width / 2. + 0.5); int bottom = int(item.centery + item.height / 2. + 0.5); int vtop = (int)(item.centery - item.height*0.75 + 0.5); /*******************统计字符区域属性************************************/ int cl = left + ((right - left + 1) + 2) / 4; int cr = left + ((right - left + 1) * 3 + 2) / 4; int ct = top; int cb = bottom; //初始化字符区域参数 char_area_avg_gray = 0; char_area_black_count = 0; char_area_size = 0; for (int y = ct; y <= cb; y++) { for (int x = cl; x <= cr; x++) { gray = ggray(dst, x, y); char_area_size++; if (gray0)char_area_avg_gray /= char_area_black_count; //灰度直方图 int gray256[260]; cellSize = 0; memset(gray256, 0, sizeof(gray256)); double yRatio, xRatio, maxRatio; double dist; if (item.width >= item.height){ xRatio = 1.0; yRatio = (item.width / (double)item.height)*(1 - 0.3); if (yRatio<1)yRatio = 1; } else{ yRatio = 1.0; xRatio = (item.height / (double)item.width)*(1 - 0.3); if (xRatio<1)xRatio = 1; } double yd = item.centery; double xd = item.centerx; //理想点数 int li_xiang_dian_shu = item.width*item.height; double dx; double dy; maxRatio = sqrt(xRatio*xRatio + yRatio*yRatio); xRatio = xRatio / (item.width / 2.0); yRatio = yRatio / (item.height / 2.0); xRatio = xRatio / maxRatio; yRatio = yRatio / maxRatio; refArea = 0; double distSum = 0; avg_gray = 0; grayNum = 0; for (int y = top; y <= bottom; y++) { for (int x = left; x <= right; x++) { gray = ggray(dst, x, y); gray256[gray]++; cellSize++; if (gray0 ? avg_gray / grayNum : 256; refArea /= 16; refArea /= distSum; //灰度上限 int grayUp = 256 - schemaPage.hei_du_ling_min_du * 16; mo_hu_du = 0; //合格黑点数 int he_ge_hei_dian_shu = 0; for (int i = 0; i0){ he_ge_hei_dian_shu += gray256[i]; mo_hu_du += (i*gray256[i]); } } mo_hu_du = he_ge_hei_dian_shu>0 ? mo_hu_du / he_ge_hei_dian_shu : 0; double ping_jun_hei_du = he_ge_hei_dian_shu>0 ? mo_hu_du / he_ge_hei_dian_shu : 0; int i, endpos, flag = 0; int hui_du_he = 0; int hei_dian_shu = 0; for (i = 0, endpos = grayUp; i0){ if (flag == 0){ flag = 1; endpos = min(grayUp, i + 40); } hui_du_he += (i*gray256[i]); hei_dian_shu += gray256[i]; } if (hei_dian_shu>li_xiang_dian_shu*0.1 || hei_dian_shu >= he_ge_hei_dian_shu*0.3 + 1){ endpos = i; i++; break; } } for (; i= he_ge_hei_dian_shu*0.3 + 1; i++) { hui_du_he += (i*gray256[i]); hei_dian_shu += gray256[i]; } endpos = i; gao_heidu = hei_dian_shu>0 ? (255 - hui_du_he / hei_dian_shu) / 16 : 0; refArea /= max(1.0, gao_heidu - 2); /************确定清晰度**************************/ int pnt_high = 0, pnt_low = 0, pnt_mid = 0; int pos1, pos2, pos3; double minRatio = 0.3; maxRatio = 0.8; pos1 = 255 - (int)(gao_heidu*maxRatio * 16); for (i = 0; i <= pos1; i++) { pnt_high += gray256[i]; } for (i = pos1 + 1; i= 3 ? 255 - (int)(gao_heidu*minRatio * 16) : 255 - 48; pos3 = min(pos2, pos1 + 16); for (i = pos1 + 1; i <= pos3; i++) { pnt_mid += gray256[i]; } for (i = pos3 + 1; i <= pos2; i++) { pnt_low += gray256[i]; } if (pnt_high == 0){ return identify::result::IDF_DIVIDE_ZERO; } mo_hu_du = ((pnt_low + pnt_mid) / (double)pnt_high + pnt_low / (double)(pnt_high + pnt_mid)) / 2.0; mo_hu_du = min(mo_hu_du, gao_heidu - ping_jun_hei_du); mo_hu_du = min(min(gao_heidu, mo_hu_du), 5.0); return identify::result::IDF_SUCCESS; } //分析全局属性 int COnLineCardPageIdentifier::analyseOmrPanoramic(SchemaPage& schemaPage) { int i; int lev; int count; // 所有涂点个数 int numAblePnt; // 参与分析的点的个数 double maxblk[16]; int numBlk[16]; double maxBlur[16]; int numBlur[16]; double stdBlur; memset(numBlk, 0, sizeof(int) * 16); memset(maxblk, 0, sizeof(double) * 16); memset(maxBlur, 0, sizeof(double) * 16); memset(numBlur, 0, sizeof(int) * 16); count = schemaPage.itemCount; numAblePnt = 0; double& m_avaMaxBlk = anlyseResult.avgMax_heidu; double& m_benchmarkBlk = anlyseResult.benchmarkBlk; double& m_benchmarkArea = anlyseResult.benchmarkAreaBlk; m_avaMaxBlk = 0; for (i = 0; i 0) m_avaMaxBlk /= numAblePnt; else m_avaMaxBlk = 12; int stdId = 2; int numStd = numBlk[0] + numBlk[1] + numBlk[2]; int numCur = numStd; for (i = 3; i<16; i++) { numCur += (numBlk[i] - numBlk[i - 3]); if (numCur > numStd) { numStd = numCur; stdId = i; } } double stdBlk = maxblk[stdId - 2] + maxblk[stdId - 1] + maxblk[stdId]; if (numStd > 0) stdBlk /= numStd; else stdBlk = 12; // 计算模糊度代表值 stdId = 2; numStd = numBlur[0] + numBlur[1] + numBlur[2]; numCur = numStd; for (i = 3; i<16; i++) { numCur += (numBlur[i] - numBlur[i - 3]); if (numCur > numStd) { numStd = numCur; stdId = i; } } stdBlur = maxBlur[stdId - 2] + maxBlur[stdId - 1] + maxBlur[stdId]; if (numStd > 0) stdBlur /= numStd; else stdBlur = 0; if (stdBlur < 2.0) stdBlk -= stdBlur; else stdBlk -= 2.0; if (stdBlk < m_avaMaxBlk) m_avaMaxBlk = stdBlk; //统计字符区域的黑色点数的平均值 if (schemaPage.groupCount>0){ int max_item = 1; for (int gi = 0; gimax_item) max_item = schemaPage.groups[gi].itemCount; } int * char_area_black_counts = new int[schemaPage.groupCount]; int cur_item_count;//当前选项的数量 for (int ii = 0; iiii){ OnlineAnalyseResult::itemResult& ir = anlyseResult.itemAnalyseResult[schemaPage.groups[gi].itemIndex[ii]]; char_area_black_counts[cur_item_count] = ir.char_area_black_count; total_char_area_size += ir.char_area_size; cur_item_count++; } } double char_area_size_avg = total_char_area_size / (double)cur_item_count; int temp; for (int m = 0; mgroup_result.resize(schemaPage.groups.size()); identify::result::KEGUANTI_RESULT* ketuanti_result_value = omr_result->group_result.data(); //标记是否被选中 SelectType sel[MAX_ITEM]; for (int groupIndex = 0; groupIndexgray_num > maxgraynum)maxgraynum = results[i]->gray_num; if (results[i]->gray_num < mingraynum)mingraynum = results[i]->gray_num; } int selected_num = 0; int unselect_num = 0; int uncertain_num = 0; for (int i = 0; igray_numcell_size*0.1){ sel[i] = UNSELECT; unselect_num++; continue; } //面积超过65% if (results[i]->gray_num>results[i]->cell_size*0.65){ sel[i] = SELECTED; selected_num++; continue; } //填涂面积相差达%15,将面积不小于最大点填涂面积的总面积%10的涂点视为填涂 if (maxgraynum - mingraynum>results[i]->cell_size*0.2&&results[i]->gray_num>maxgraynum - results[i]->cell_size*0.1){ sel[i] = SELECTED; selected_num++; continue; } //填涂面积相差达%50,将面积不小于最大点填涂面积的总面积%30的涂点视为填涂 if (maxgraynum - mingraynum>results[i]->cell_size*0.5&&results[i]->gray_num>maxgraynum - results[i]->cell_size*0.3){ sel[i] = SELECTED; selected_num++; continue; } if (maxgraynum - results[i]->gray_num>results[i]->cell_size*0.2){ sel[i] = UNSELECT; unselect_num++; continue; } sel[i] = UNCERTAIN; uncertain_num++; } int out_count; identify::result::OMR_QUESTION_STATE question_state = identify::result::OMR_QUESTION_STATE::OMR_QUESTION_STATE_NORMAL; if (group.omr_out_type == OMR_OUT_TYPE::OMR_OUT_TYPE_SINGLE_NONSTRICT){ if (selected_num>1){ int maxgrayindex = -1; int maxgraynum = -101; for (int i = 0; igray_num - maxgraynum>100) || (abs(results[i]->gray_num - maxgraynum) <= 100 && results[i]->heidu > results[maxgrayindex]->heidu)) { maxgraynum = results[i]->gray_num; maxgrayindex = i; } } } for (int i = 0; i0)omr_str[omr_str_len++] = schemaPage.option_spacer; omr_str[omr_str_len++] = items[i]->OutChar; out_count++; } } if (out_count == 0){ omr_str[omr_str_len++] = schemaPage.unselect_char; question_state = identify::result::OMR_QUESTION_STATE::OMR_QUESTION_STATE_LOUTU; } } else if (group.omr_out_type == OMR_OUT_TYPE::OMR_OUT_TYPE_MUTIL_STRICT) { out_count = 0; for (int i = 0; i < pn; i++) { if (sel[i] == SELECTED){ if (out_count > 0)omr_str[omr_str_len++] = schemaPage.option_spacer; omr_str[omr_str_len++] = items[i]->OutChar; out_count++; } } if (out_count == 0){ omr_str[omr_str_len++] = schemaPage.unselect_char; question_state = identify::result::OMR_QUESTION_STATE::OMR_QUESTION_STATE_LOUTU; } } omr_str[omr_str_len] = '\0'; ketuanti_result_value[groupIndex].question_code = group.question_code; ketuanti_result_value[groupIndex].obj_id = static_cast(group.question_index); ketuanti_result_value[groupIndex].answer = omr_str; ketuanti_result_value[groupIndex].question_state = identify::result::OMR_QUESTION_STATE::OMR_QUESTION_STATE_NORMAL; ketuanti_result_value[groupIndex].omr_question_type = group.omr_out_type == OMR_OUT_TYPE::OMR_OUT_TYPE_SINGLE_NONSTRICT ? identify::DANXUANTI :identify::DUOXUANTI ; } return 0; } // //识别指定图像 int COnLineCardPageIdentifier::Identify(const IplImage* img, void* out_result, int out_size) { if (out_result){ this->out_result = out_result; this->omr_result = (identify::result::OMR_RESULT*)this->out_result; // printf("线程:%s 缓冲区:缺考标记:%d %p\n", std::to_string(GetCurrentThreadId()).c_str(), omr_result->quekaoFlag, this->out_result); src = (IplImage*)img; if (src == NULL) return identify::result::IDF_FAILURE; }else{ return identify::result::IDF_FAILURE; } return Identify(); } /************************************************************************/ /* 获取区域黑色点数量 */ /************************************************************************/ int COnLineCardPageIdentifier::GetBlackArea(const IplImage * dst) { int blackArea = 0; CvRect rect = cvGetImageROI(dst); int(*GetGray)(const IplImage * dst, int x, int y); if (dst->nChannels == 1)GetGray = GetGrayValue; else GetGray = GetBGRGray; for (int y = rect.y, endy = rect.y + rect.height; ywidth<200 || src->height<200){ return identify::result::IDF_SIZE2SMALL; } if (abs(max(src->width, src->height) / (double)min(src->width, src->height) - max(21.0, 27.9) / (double)min(21.0, 27.9))>0.2){ //图像长宽比不符 return identify::result::IDF_SIDERATIO; } return identify::result::IDF_SUCCESS; } /* 临时变量初始化 */ void COnLineCardPageIdentifier::InitalizeTempVar() { m_relationKey.clear(); m_relationValue.clear(); } // 读取学生学号 int COnLineCardPageIdentifier::ReadStudentID(SchemaPage &schemaPage, IplImage * dst) { omr_result->qr_result.clear(); identify::result::CODE_RESULT code_rst; code_rst.qr_str = ""; code_rst.is_stu_id = false; if (strlen(schemaPage.student_code)>0){ code_rst.qr_str = schemaPage.student_code; code_rst.is_stu_id = schemaPage.is_stu_id; }else{ m_items = schemaPage.stuItems; // 计算每个填图区域图像信息 int global_background_color_avg = caculate_global_background(schemaPage, dst, true); //模糊度,面积,高黑度,平均黑度 double mo_hu_du, refArea, gao_heidu, avg_gray; //黑色像素数,涂点大小 int grayNum, cellSize; //高黑度和 double topGraySum = 0; //高黑度面积 double topGrayAreaSum = 0; anlyseResult.backGroundGray = global_background_color_avg; anlyseResult.cellAvgGray = 0; anlyseResult.cellNum = 0; int numTopGray = 0; int ret; item_result.resize(schemaPage.stuItemCount); for (int i = 0; i < schemaPage.stuItemCount; i++) { SchemaItem & item = m_items[i]; item_result[i] = GetCVRect(item); ret = caculate_cell_property(schemaPage, item, dst, cellSize, refArea, avg_gray, grayNum, mo_hu_du, gao_heidu, anlyseResult.itemAnalyseResult[i].char_area_size, anlyseResult.itemAnalyseResult[i].char_area_black_count, anlyseResult.itemAnalyseResult[i].char_area_avg_gray); if (ret != identify::result::IDF_SUCCESS)return ret; topGraySum += gao_heidu; topGrayAreaSum += refArea; numTopGray++; anlyseResult.cellAvgGray += avg_gray; anlyseResult.cellNum++; anlyseResult.itemAnalyseResult[i].avg_gray = avg_gray; anlyseResult.itemAnalyseResult[i].cell_size = cellSize; anlyseResult.itemAnalyseResult[i].gray_num = grayNum; anlyseResult.itemAnalyseResult[i].heidu = gao_heidu; anlyseResult.itemAnalyseResult[i].mohudu = mo_hu_du; anlyseResult.itemAnalyseResult[i].xiangdui_mianji = refArea; anlyseResult.itemAnalyseResult[i].xiangdui_value = refArea; } anlyseResult.cellAvgGray = anlyseResult.cellNum > 0 ? anlyseResult.cellAvgGray / anlyseResult.cellNum : 256; anlyseResult.avg_heidu = topGrayAreaSum > 0 ? topGraySum / topGrayAreaSum : 6; if (numTopGray >= int(schemaPage.itemCount / 5)){ anlyseResult.float_heidu = anlyseResult.avg_heidu / schemaPage.user_float_heidu; anlyseResult.benchmarkBlk = schemaPage.worthwhileBlk + anlyseResult.float_heidu; } else{ anlyseResult.benchmarkBlk = numTopGray > 0 ? min(6.0, schemaPage.worthwhileBlk + anlyseResult.avg_heidu / schemaPage.user_float_heidu) : 6; anlyseResult.float_heidu = anlyseResult.benchmarkBlk - schemaPage.worthwhileBlk; } if (numTopGray > 0){ anlyseResult.avg_heidu = topGrayAreaSum / numTopGray; anlyseResult.float_heidu = anlyseResult.avg_heidu / schemaPage.user_float_heidu; anlyseResult.benchmarkAreaBlk = anlyseResult.float_heidu; } else{ anlyseResult.avg_heidu = 0; anlyseResult.float_heidu = 0; anlyseResult.benchmarkAreaBlk = 0.1; } // 获取 std::string strStudent; if (GenerateOmrStr(schemaPage, strStudent) == 0){ code_rst.qr_str = strStudent; } } if (!code_rst.qr_str.empty()) omr_result->qr_result.push_back(code_rst); omr_result->online_card_paperid = schemaPage.paper_id; omr_result->schoolCardStatus = schemaPage.schoolCardStatus; if (m_bUseQr) { std::vector split_qr; split(m_strQrClass, (std::string)",", &split_qr); if (split_qr.size()>1&& !split_qr[1].empty()){ omr_result->paper_id = std::stoi(split_qr[1]); } } else{ omr_result->paper_id = -1; } return identify::result::IDF_SUCCESS; } //读取客观题分数 int COnLineCardPageIdentifier::ReadKeGuanTi(SchemaPage &schemaPage, IplImage * dst) { m_items = schemaPage.items; int global_background_color_avg = caculate_global_background(schemaPage, dst); //模糊度,面积,高黑度,平均黑度 double mo_hu_du, refArea, gao_heidu, avg_gray; //黑色像素数,涂点大小 int grayNum, cellSize; //高黑度和 double topGraySum = 0; //高黑度面积 double topGrayAreaSum = 0; anlyseResult.backGroundGray = global_background_color_avg; anlyseResult.cellAvgGray = 0; anlyseResult.cellNum = 0; int numTopGray = 0; int ret; item_result.resize(schemaPage.itemCount); for (int i = 0; i0 ? anlyseResult.cellAvgGray / anlyseResult.cellNum : 256; anlyseResult.avg_heidu = topGrayAreaSum>0 ? topGraySum / topGrayAreaSum : 6; if (numTopGray >= int(schemaPage.itemCount / 5)){ anlyseResult.float_heidu = anlyseResult.avg_heidu / schemaPage.user_float_heidu; anlyseResult.benchmarkBlk = schemaPage.worthwhileBlk + anlyseResult.float_heidu; } else{ anlyseResult.benchmarkBlk = numTopGray>0 ? min(6.0, schemaPage.worthwhileBlk + anlyseResult.avg_heidu / schemaPage.user_float_heidu) : 6; anlyseResult.float_heidu = anlyseResult.benchmarkBlk - schemaPage.worthwhileBlk; } if (numTopGray>0){ anlyseResult.avg_heidu = topGrayAreaSum / numTopGray; anlyseResult.float_heidu = anlyseResult.avg_heidu / schemaPage.user_float_heidu; anlyseResult.benchmarkAreaBlk = anlyseResult.float_heidu; } else{ anlyseResult.avg_heidu = 0; anlyseResult.float_heidu = 0; anlyseResult.benchmarkAreaBlk = 0.1; } analyseOmrPanoramic(schemaPage); GenerateOmrStr(schemaPage); return identify::result::IDF_SUCCESS; } //读取填空题,和主观题分数 int COnLineCardPageIdentifier::ReadQuestionScore(SchemaPage &schemaPage, IplImage * dst, CvMemStorage* storage) { int tiankong_total_count = 0; int zhuguan_total_count = 0; for (int i = 0; itiankongti_result.resize(tiankong_total_count); omr_result->zhutuanti_result.resize(zhuguan_total_count); identify::result::TIANKONGTI_RESULT*tiankongti_result_value = omr_result->tiankongti_result.data(); identify::result::ZHUGUANTI_RESULT*zhutuanti_result_value = omr_result->zhutuanti_result.data(); int score_count = 0; int tiankong_count = 0; for (int i = 0; idata.fl, sizeof(float) * 6); cvReleaseMat(&m); SchemaQuestionScore::Point * point[4] = { &qs.lt, &qs.rt, &qs.lb, &qs.rb }; float lx = -1, ly = -1; float rx = -1, ry = -1; double pscale = 1.0; int redcount[30] = { 0 }; int red_in_count[30] = { 0 }; lx = data[0] * qs.lt.x + data[1] * qs.lt.y + data[2]; rx = data[0] * qs.rt.x + data[1] * qs.rt.y + data[2]; ly = data[3] * qs.lt.x + data[4] * qs.lt.y + data[5]; ry = data[3] * qs.rt.x + data[4] * qs.rt.y + data[5]; if (qs.type == QUESTION_SCORE_TYPE::MUTIL_SCORE){ if (lx >= 0 && rx >= 0){ float h = (point[2]->y - point[0]->y)*pscale; CvRect detect_rect = cvRect(qs.scoreBox.pos.x, qs.scoreBox.pos.y, qs.scoreBox.pos.w, qs.scoreBox.pos.h); GetZhuGuanTiRedCount(dst, detect_rect, detect_rect, redcount, red_in_count, qs.count, qs.scoreBox.type != 1 || qs.scoreBox.bPoint, false); float score = 0; if (qs.scoreBox.type == 1) { // 小数位 if (qs.scoreBox.bPoint){ if (red_in_count[0] > 25){ score += 0.5; } } // 整数位 { int red_area = 0; int red_area_index = -1; for (int i = (qs.scoreBox.bPoint ? 1 : 0); i < qs.count; ++i) { if (red_in_count[i]>red_area){ red_area = red_in_count[i]; red_area_index = i; } } if (red_area_index >= (qs.scoreBox.bPoint ? 1 : 0)){ score += (qs.scoreBox.limit - red_area_index + (qs.scoreBox.bPoint ? 1 : 0)); } } } else if (qs.scoreBox.type == 2) { // 小数位 if (qs.scoreBox.bPoint){ if (red_in_count[0] > 25){ score += 0.5; } } { //个位数 int red_area = 0; int red_area_index = -1; for (int i = (qs.scoreBox.bPoint ? 1 : 0); i < (qs.scoreBox.bPoint ? 11 : 10); ++i) { if (red_in_count[i]>red_area){ red_area = red_in_count[i]; red_area_index = i; } } if (red_area_index >= (qs.scoreBox.bPoint ? 1 : 0)){ score += (9 - red_area_index + (qs.scoreBox.bPoint ? 1 : 0)); } } { //十位数 int red_area = 0; int red_area_index = -1; int begin_index = (qs.scoreBox.bPoint ? 11 : 10); for (int i = begin_index; i < begin_index + (int)(qs.scoreBox.limit / 10) + 1; ++i) { if (red_in_count[i] > red_area){ red_area = red_in_count[i]; red_area_index = i; } } if (red_area_index >= begin_index){ score = score + 10 * ((int)(qs.scoreBox.limit / 10) - (red_area_index - begin_index) + 1); } } } zhutuanti_result_value[score_count].question_score = score; zhutuanti_result_value[score_count].question_state = identify::result::OMR_QUESTION_STATE::OMR_QUESTION_STATE_NORMAL; } else{ zhutuanti_result_value[score_count].question_score = 0; zhutuanti_result_value[score_count].question_state = identify::result::OMR_QUESTION_STATE::OMR_QUESTION_STATE_WUFASHIBIE; } zhutuanti_result_value[score_count].obj_id = static_cast(qs.question_index); zhutuanti_result_value[score_count].question_code = qs.question_code; zhutuanti_result_value[score_count].omr_question_type = identify::OMR_QUESTION_TYPE::ZHUTUANTI; zhutuanti_result_value[score_count].total = 0; zhutuanti_result_value[score_count].required = 0; zhutuanti_result_value[score_count].xuanze = -1; if (qs.scoreBox.bXuanZuoTi){ zhutuanti_result_value[score_count].omr_question_type = identify::OMR_QUESTION_TYPE::XUANZUOTI; zhutuanti_result_value[score_count].total = qs.countNum; zhutuanti_result_value[score_count].required = qs.countItemSelete; zhutuanti_result_value[score_count].xuanze = ReadXuanZuoTi(schemaPage, qs, dst); zhutuanti_result_value[score_count].question_code_all = qs.question_code_all; } score_count++; } else { if (lx >= 0 && rx >= 0){ if (qs.count > 1){ float score = 0; int red_area_index = -1; // 在线答题卡-填空题 if (qs.scoreBox.type == 3){ float h = (point[2]->y - point[0]->y)*pscale; CvRect detect_rect = cvRect(qs.scoreBox.pos.x, qs.scoreBox.pos.y, qs.scoreBox.pos.w, qs.scoreBox.pos.h); GetZhuGuanTiRedCount(dst, detect_rect, detect_rect, redcount, red_in_count, qs.count, 0, true); int red_area = 0; for (int m = 0; mred_area&&red_in_count[m]>25){ red_area = red_in_count[m]; red_area_index = m; } } if (red_area_index >= 0 && static_cast(qs.scoreBox.vctScore.size())>red_area_index){ score = qs.scoreBox.vctScore.at(qs.count - red_area_index - 1); } } tiankongti_result_value[tiankong_count].question_score = score; tiankongti_result_value[tiankong_count].omr_question_type = identify::OMR_QUESTION_TYPE::TIANKONGTI2; }else{ float w = (rx - lx) / qs.count; float h = (point[2]->y - point[0]->y)*pscale; for (int j = 0; j<1; j++){ CvRect rect_detect = cvRect(qs.scoreBox.pos.x, qs.scoreBox.pos.y, qs.scoreBox.pos.w, qs.scoreBox.pos.h); int red_area = GetTianKongTiRedCount(dst, rect_detect, rect_detect, 1, 0); if (red_area>25){ tiankongti_result_value[tiankong_count].isright = TRUE; break; } else{ tiankongti_result_value[tiankong_count].isright = FALSE; } } tiankongti_result_value[tiankong_count].omr_question_type = identify::OMR_QUESTION_TYPE::TIANKONGTI; } }else{ tiankongti_result_value[tiankong_count].isright = FALSE; if (qs.count > 1) { tiankongti_result_value[tiankong_count].omr_question_type = identify::OMR_QUESTION_TYPE::TIANKONGTI2; } else { tiankongti_result_value[tiankong_count].omr_question_type = identify::OMR_QUESTION_TYPE::TIANKONGTI; } } tiankongti_result_value[tiankong_count].obj_id = static_cast(qs.question_index); tiankongti_result_value[tiankong_count].question_code = qs.question_code; tiankong_count++; } } return identify::result::IDF_SUCCESS; } //截取图像 int COnLineCardPageIdentifier::ClipImg(SchemaPage& schemaPage, IplImage * dst) { cvResetImageROI(dst); vector compression_params; compression_params.push_back(CV_IMWRITE_JPEG_QUALITY); compression_params.push_back(60); omr_result->cut_area_result.resize(schemaPage.cutAreaCount); identify::result::CUT_AREA_RESULT* cut_area_result_value = omr_result->cut_area_result.data(); for (int i = 0; i dst; cv::Mat _img = cvarrToMat(img); imencode(".jpg", _img, dst, compression_params); cut_area_result_value[i].obj_id = cutArea.index; cut_area_result_value[i].area_index = cutArea.index; cut_area_result_value[i].area_sub_index = cutArea.isfirst?1:0; cut_area_result_value[i].centerx = cutArea.centerx; cut_area_result_value[i].centery = cutArea.centery; cut_area_result_value[i].width = cutArea.width; cut_area_result_value[i].height = cutArea.height; cut_area_result_value[i].area_name = cutArea.area_name; cut_area_result_value[i].is_cut = cutArea.iscut; cut_area_result_value[i].img_data.resize(dst.size()); memcpy(cut_area_result_value[i].img_data.data(), &dst[0], dst.size()); cvReleaseImage(&img); } return identify::result::IDF_SUCCESS; } //获取图像指定区域红色点数(主观题) 去除长直线和周边像素 减少直线边缘偏色影响 int COnLineCardPageIdentifier::GetZhuGuanTiRedCount(IplImage * dst, const CvRect& rect, const CvRect& normal_rect, int * red_counts, int * red_in_counts, int count, int mutil, bool bTianKongTi /*= false*/) { if (count >= 30) return 0; if (dst->nChannels != 3){ return 0; } if (m_nXianXiaDaFenType == 1) { memset(red_counts, 0, sizeof(int)*count); memset(red_in_counts, 0, sizeof(int)*count); cvSetImageROI(dst, rect); Mat img= cv::cvarrToMat(dst); cvResetImageROI(dst); int tempi[50] = { 0 }; try{ EnterCriticalSection(m_althom_rcs); // printf("线程:%s 新算法判分-开始\n", std::to_string(GetCurrentThreadId()).c_str()); if (api_red_check_analysis(img, count, bTianKongTi ? 3 : 2, mutil, tempi, count) != 0) { // printf("线程:%s 新算法判分-错误\n", std::to_string(GetCurrentThreadId()).c_str()); LeaveCriticalSection(m_althom_rcs); return 0; } // printf("线程:%s 新算法判分-结束\n", std::to_string(GetCurrentThreadId()).c_str()); LeaveCriticalSection(m_althom_rcs); } catch (cv::Exception&e){ // printf("线程:%s 新算法判分-异常\n", std::to_string(GetCurrentThreadId()).c_str()); LeaveCriticalSection(m_althom_rcs); #if 0 static const char* str; str = e.what(); #endif } for (int i = 0; i < count; i++) { red_in_counts[i] = tempi[count - i - 1]; if (red_in_counts[i] > 0) { red_counts[i] = 30; //目的大于25 } } return identify::result::IDF_SUCCESS; } IplImage* red = NULL; BOOL s = GetRedBinary(dst, rect, &red); if (!s)return 0; IplImage * temp = cvCloneImage(red); CvMemStorage* storage = cvCreateMemStorage(); CvSeq* contours = NULL; cvFindContours(temp, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0)); int top = normal_rect.y - rect.y; int bottom = normal_rect.y + normal_rect.height - 1 - rect.y; for (CvContour * c = (CvContour *)contours; c != NULL; c = (CvContour *)c->h_next) { CvRect b_rect = cvBoundingRect(c); if (b_rect.y>bottom - 1 || b_rect.y + b_rect.height - 1width; int h = red->height; for (int x = 0; x= top + 1){ red_in_counts[option_index]++; } } } } cvReleaseImage(&red); return identify::result::IDF_SUCCESS; } //获取图像指定区域红色点数(填空题) int COnLineCardPageIdentifier::GetTianKongTiRedCount(IplImage * dst, const CvRect& rect_normal, const CvRect& rect_detect,int count,int multi) { CvRect rect = cvGetImageROI(dst); if (dst->nChannels != 3){ return 0; } if (m_nXianXiaDaFenType == 1){ cvSetImageROI(dst, rect_detect); Mat img = cv::cvarrToMat(dst); cvResetImageROI(dst); int tempi[50] = { 0 }; try{ EnterCriticalSection(m_althom_rcs); // printf("线程:%s 新算法判分-开始\n", std::to_string(GetCurrentThreadId()).c_str()); int fff = api_red_check_analysis(img, count, 3, multi, tempi, count); if (fff != 0){ // printf("线程:%s 新算法判分-错误\n", std::to_string(GetCurrentThreadId()).c_str()); LeaveCriticalSection(m_althom_rcs); return 0; } // printf("线程:%s 新算法判分-结束\n", std::to_string(GetCurrentThreadId()).c_str()); LeaveCriticalSection(m_althom_rcs); } catch (cv::Exception&e){ // printf("线程:%s 新算法判分-异常\n", std::to_string(GetCurrentThreadId()).c_str()); LeaveCriticalSection(m_althom_rcs); #if 0 static const char* str; str = e.what(); #endif } if (tempi[0] > 0) return 300; return 0; } int w = rect_detect.width; int h = rect_detect.height; IplImage * red = NULL; BOOL r = GetRedBinary(dst, rect_detect, &red); if (!r)return 0; vector redPoints; for (int y = 0; yheight; y++) { unsigned char * red_row_first = (unsigned char *)(red->imageData + (y*red->widthStep)); for (int x = 0; xwidth; x++) { if (red_row_first[x]){ redPoints.push_back(cvPoint2D32f(x, y)); } } } CvMemStorage * storage = cvCreateMemStorage(); CvSeq* contour = NULL; int contours = cvFindContours(red, storage, &contour, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE); int red_count = 0; int normal_left = rect_normal.x - rect_detect.x; int normal_top = rect_normal.y - rect_detect.y; int normal_right = normal_left + rect_normal.width; int normal_bottom = normal_top + rect_normal.height; for (CvContour * c = (CvContour *)contour; c != NULL; c = (CvContour *)c->h_next){ float sum_x = 0; float sum_y = 0; int in_count = 0; int area_c = 0;//轮廓在评分框内的点数 for (std::size_t i = 0; i= 0){ sum_x += redPoints[i].x; sum_y += redPoints[i].y; in_count++; if (normal_left <= redPoints[i].x&&redPoints[i].x <= normal_right&&normal_top <= redPoints[i].y&&redPoints[i].y <= normal_bottom){ area_c++; } } } if (in_count == 0)continue; if (area_c>60){ red_count += in_count; continue; } //重心位置 float avg_x = sum_x / in_count; float avg_y = sum_y / in_count; if (normal_left <= avg_x&&avg_x <= normal_right + 30 && normal_top <= avg_y&&avg_y <= normal_bottom){ red_count += in_count; } } cvReleaseImage(&red); cvReleaseMemStorage(&storage); return red_count; } int COnLineCardPageIdentifier::SaveLocateInfo(SchemaPage& schemaPage, vector &relationKey, vector &relationValue) { if (relationKey.size() >= 2) { m_relationKey = relationKey; m_relationValue = relationValue; double distance = 0; int index1; int index2; for (std::size_t i = 0; idistance){ distance = d; index1 = i; index2 = j; } } } //模板上的定位点 CvPoint2D32f *p11 = &m_relationKey[index1]; CvPoint2D32f *p12 = &m_relationKey[index2]; //试卷上的定位点 CvPoint2D32f*p21 = &m_relationValue[index1]; CvPoint2D32f*p22 = &m_relationValue[index2]; CvMat* m_m = caculate_scm(*p21, *p22, *p11, *p12); memcpy(data, m_m->data.fl, sizeof(float) * 6); cvReleaseMat(&m_m); return identify::result::IDF_SUCCESS; } return identify::result::IDF_NOTFOUND_ENOUGH_LOCATEPOINT; } int COnLineCardPageIdentifier::GetRect(const int centerx, const int centery, const int width, const int height, RESULT_RECT& result_rect) { result_rect.x = centerx - width / 2; result_rect.y = centery - height / 2; result_rect.width = width; result_rect.height = height; return identify::result::IDF_FAILURE; } int COnLineCardPageIdentifier::GetRect2(const int centerx, const int centery, const int width, const int height, RESULT_RECT& result_rect) { double x = data[0] * centerx + data[1] * centery + data[2]; double y = data[3] * centerx + data[4] * centery + data[5]; result_rect.x = (int)(x - width / 2 + 0.5); result_rect.y = (int)(y - height / 2 + 0.5); result_rect.width = width; result_rect.height = height; return identify::result::IDF_SUCCESS; } template void COnLineCardPageIdentifier::SaveRect(CvRect& rect, T& result) { result.centerx = static_cast(rect.x + rect.width / 2.0); result.centery = static_cast(rect.y + rect.height / 2.0); result.width = static_cast(rect.width); result.height = static_cast(rect.height); result.angle = 0; } template void COnLineCardPageIdentifier::DrawObjRect(IplImage * dst, T& obj_result, CvScalar& scalar) { cvDrawRect(dst, cvPoint(obj_result.centerx - obj_result.width / 2, obj_result.centery - obj_result.height / 2), cvPoint(obj_result.centerx + obj_result.width / 2, obj_result.centery + obj_result.height / 2), scalar); } //查找题目定位点 BOOL COnLineCardPageIdentifier::FindQuestionLocatePoint(IplImage * dst, SchemaLocatePoint& lp1, CvPoint2D32f& point1) { int top = max(0, (int)(lp1.centery - lp1.height*1.5 + 0.5)); int bottom = min(dst->height - 1, (int)(lp1.centery + lp1.height*1.5 + 0.5)); int left = max(0, (int)(lp1.centerx - lp1.width*1.5 + 0.5)); int right = min(dst->width - 1, (int)(lp1.centerx + lp1.width*1.5 + 0.5)); int x = left; int y = top; int width = right - left + 1; int height = bottom - top + 1; if (width<1 || height<1)return FALSE; IplImage* dst_gray_img = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); IplImage* dst_binary_img = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); CvMemStorage* storage = cvCreateMemStorage(); cvSetImageROI(dst, cvRect(x, y, width, height)); if (dst->nChannels == 3)cvCvtColor(dst, dst_gray_img, CV_BGR2GRAY); else cvCopy(dst, dst_gray_img); cvThreshold(dst_gray_img, dst_binary_img, 180, 255, CV_THRESH_BINARY); int an = 2; IplConvKernel * element = cvCreateStructuringElementEx(an * 2 + 1, an * 2 + 1, an, an, CV_SHAPE_RECT, 0);//创建结构元素 cvDilate(dst_binary_img, dst_binary_img, element, 1);//膨胀图像 cvErode(dst_binary_img, dst_binary_img, element, 1);//腐蚀图像 cvReleaseStructuringElement(&element); CvSeq * pcontours = NULL; int ncontours = cvFindContours(dst_binary_img, storage, &pcontours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE); vector quesiontLocatePoints; for (CvContour * c = (CvContour *)pcontours; c != NULL; c = (CvContour *)c->h_next) { if (c->rect.widthrect.heightrect.width>lp1.width + 3)continue; if (c->rect.height>lp1.height + 3)continue; cvSetImageROI(dst_gray_img, c->rect); int area = GetBlackArea(dst_gray_img); if (arearect.width*c->rect.height*0.75)continue; quesiontLocatePoints.push_back(c); } double distance = 99999; int min_index = -1; for (std::size_t i = 0; irect.x + quesiontLocatePoints[i]->rect.width / 2.0, quesiontLocatePoints[i]->rect.y + quesiontLocatePoints[i]->rect.height / 2.0)); if (d= 0){ point1 = cvPoint2D32f(quesiontLocatePoints[min_index]->rect.x + quesiontLocatePoints[min_index]->rect.width / 2.0 + x, quesiontLocatePoints[min_index]->rect.y + quesiontLocatePoints[min_index]->rect.height / 2.0 + y); cvReleaseImage(&dst_gray_img); cvReleaseImage(&dst_binary_img); cvReleaseMemStorage(&storage); return TRUE; } cvReleaseImage(&dst_gray_img); cvReleaseImage(&dst_binary_img); cvReleaseMemStorage(&storage); return FALSE; } double COnLineCardPageIdentifier::GetDistance(CvPoint2D32f point1, CvPoint2D32f point2) { double dx = point1.x - point2.x; double dy = point1.y - point2.y; return sqrt(dx*dx + dy*dy); } int COnLineCardPageIdentifier::FindQuestionLocatePoints(SchemaPage& schemaPage, IplImage * dst) { std::vector& questionLocatePoints = schemaPage.questionLocatePoints; m_question_locate_points.resize(questionLocatePoints.size()); m_question_locate_point_found.resize(questionLocatePoints.size()); for (std::size_t i = 0; inChannels != 3)return FALSE; int w = rect_detect.width; int h = rect_detect.height; IplImage * hsv = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 3); //存储灰度图像和二值化图像 IplImage * gray = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1); IplImage * black = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1); IplImage * black_dilate = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1); //记录较浅一些的红色 IplImage * red_low = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1); //记录较深一些的红色 IplImage * red_high = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1); IplImage * red = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1); cvSetImageROI(dst, rect_detect); #if GETREDBINARY_DEBUG cvSaveImage("D:\\dst.png", dst); #endif cvCvtColor(dst, hsv, CV_BGR2HSV); cvCvtColor(dst, gray, CV_BGR2GRAY); cvAdaptiveThreshold(gray, gray, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV, 9, 10.0); rename_image(gray, binary); #define HSV_VALUE_H hsv_row_first[hsv_offset] #define HSV_VALUE_S hsv_row_first[hsv_offset+1] #define HSV_VALUE_V hsv_row_first[hsv_offset+2] const int hsv_v_valve = 255 * 50 / 100; const int hsv_h_max_valve = 180 * 20 / 360; const int hsv_h_min_valve = 180 * 315 / 360; const int hsv_s_valve_1 = 255 * 23 / 100; const int hsv_s_valve_2 = 255 * 33 / 100; const int hsv_valve_high = 255 * (23 + 70) / 100; const int hsv_valve_low = 255 * (13 + 60) / 100; for (int y = 0; yimageData + y*hsv->widthStep); unsigned char * red1_row_first = (unsigned char *)(red_low->imageData + y*red_low->widthStep); unsigned char * red2_row_first = (unsigned char *)(red_high->imageData + y*red_high->widthStep); unsigned char * binary_row_first = (unsigned char *)(binary->imageData + y*binary->widthStep); unsigned char * black_row_first = (unsigned char *)(black->imageData + y*black->widthStep); for (int x = 0, hsv_offset = 0; x= hsv_v_valve && (HSV_VALUE_H >= hsv_h_min_valve || HSV_VALUE_H <= hsv_h_max_valve)){ red1_row_first[x] = (HSV_VALUE_S >= hsv_s_valve_1 && (HSV_VALUE_S + HSV_VALUE_V) >= hsv_valve_low) ? 255 : 0; red2_row_first[x] = (HSV_VALUE_S >= hsv_s_valve_2 && (HSV_VALUE_S + HSV_VALUE_V) >= hsv_valve_high) ? HSV_VALUE_S : 0; } else{ red1_row_first[x] = red2_row_first[x] = 0; } black_row_first[x] = (binary_row_first[x] && !red1_row_first[x]) ? 255 : 0; } } #if GETREDBINARY_DEBUG cvSaveImage("D:\\hsv.png", hsv); cvSaveImage("D:\\red_low.png", red_low); cvSaveImage("D:\\red_high.png", red_high); cvSaveImage("D:\\binary.png", binary); cvSaveImage("D:\\black.png", black); #endif cvThreshold(red_high, red_high, 0, 255, CV_THRESH_OTSU); int an = 1; IplConvKernel * element = cvCreateStructuringElementEx(an * 2 + 1, an * 2 + 1, an, an, CV_SHAPE_RECT, 0);//创建结构元素 cvDilate(binary, binary, element, 2);//膨胀图像 cvDilate(red_high, red_high, element, 2);//膨胀图像 cvDilate(black, black_dilate, element, 2);//膨胀图像 for (int y = 0; yimageData + y*binary->widthStep); unsigned char * red1_row_first = (unsigned char *)(red_low->imageData + y*red_low->widthStep); unsigned char * red2_row_first = (unsigned char *)(red_high->imageData + y*red_high->widthStep); unsigned char * red_row_first = (unsigned char *)(red->imageData + y*red->widthStep); unsigned char * black_dilate_row_first = (unsigned char *)(black_dilate->imageData + y*black_dilate->widthStep); for (int x = 0; ximageData + y*red_low->widthStep); unsigned char * red_row_first = (unsigned char *)(red->imageData + y*red->widthStep); unsigned char * black_row_first = (unsigned char *)(black->imageData + y*black->widthStep); unsigned char * red_dilate_row_first = (unsigned char *)(red_dilate->imageData + y*red_dilate->widthStep); for (int x = 0; ximageData + y*red->widthStep); unsigned char * black_row_first = (unsigned char *)(black->imageData + y*black->widthStep); unsigned char * red_dilate_row_first = (unsigned char *)(red_dilate->imageData + y*red_dilate->widthStep); for (int x = 0; xnChannels == 1)GetGray = GetGrayValue; else GetGray = GetBGRGray; for (int x = left; x <= right; x++) { gray = GetGray(dst, x, vtop); if (gray>160){ background_color_avg += gray; background_color_count++; } gray = GetGray(dst, x, vbottom); if (gray>160){ background_color_avg += gray; background_color_count++; } } background_color_avg = background_color_count>0 ? background_color_avg / background_color_count : 0; if (background_color_avg>100){ global_background_color_avg += background_color_avg; global_background_color_count++; } } global_background_color_avg = global_background_color_count>0 ? global_background_color_avg / global_background_color_count : 0; return global_background_color_avg; } //选做题分析全局属性 int COnLineCardPageIdentifier::myanalyseOmrPanoramic(OnlineAnalyseResult& anlyseResultTemp, int count) { int i; int lev; //int count; // 所有涂点个数 int numAblePnt; // 参与分析的点的个数 double maxblk[16]; int numBlk[16]; double maxBlur[16]; int numBlur[16]; double stdBlur; memset(numBlk, 0, sizeof(int) * 16); memset(maxblk, 0, sizeof(double) * 16); memset(maxBlur, 0, sizeof(double) * 16); memset(numBlur, 0, sizeof(int) * 16); //count = schemaPage.itemCount; numAblePnt = 0; double& m_avaMaxBlk = anlyseResultTemp.avgMax_heidu; double& m_benchmarkBlk = anlyseResultTemp.benchmarkBlk; double& m_benchmarkArea = anlyseResultTemp.benchmarkAreaBlk; m_avaMaxBlk = 0; for (i = 0; i 0) m_avaMaxBlk /= numAblePnt; else m_avaMaxBlk = 12; int stdId = 2; int numStd = numBlk[0] + numBlk[1] + numBlk[2]; int numCur = numStd; for (i = 3; i<16; i++) { numCur += (numBlk[i] - numBlk[i - 3]); if (numCur > numStd) { numStd = numCur; stdId = i; } } double stdBlk = maxblk[stdId - 2] + maxblk[stdId - 1] + maxblk[stdId]; if (numStd > 0) stdBlk /= numStd; else stdBlk = 12; // 计算模糊度代表值 stdId = 2; numStd = numBlur[0] + numBlur[1] + numBlur[2]; numCur = numStd; for (i = 3; i<16; i++) { numCur += (numBlur[i] - numBlur[i - 3]); if (numCur > numStd) { numStd = numCur; stdId = i; } } stdBlur = maxBlur[stdId - 2] + maxBlur[stdId - 1] + maxBlur[stdId]; if (numStd > 0) stdBlur /= numStd; else stdBlur = 0; if (stdBlur < 2.0) stdBlk -= stdBlur; else stdBlk -= 2.0; if (stdBlk < m_avaMaxBlk) m_avaMaxBlk = stdBlk; //统计字符区域的黑色点数的平均值 int max_item = count; int * char_area_black_counts = new int[1]; int cur_item_count;//当前选项的数量 for (int ii = 0; ii ii){ OnlineAnalyseResult::itemResult & ir = anlyseResultTemp.itemAnalyseResult[ii]; char_area_black_counts[cur_item_count] = ir.char_area_black_count; total_char_area_size += ir.char_area_size; cur_item_count++; } } double char_area_size_avg = total_char_area_size / (double)cur_item_count; int temp; for (int m = 0; mgray_num>maxgraynum)maxgraynum = results[i]->gray_num; if (results[i]->gray_numgray_num; } int selected_num = 0; int unselect_num = 0; int uncertain_num = 0; for (int i = 0; igray_numcell_size*0.1){ sel[i] = UNSELECT; unselect_num++; continue; } //面积超过65% if (results[i]->gray_num>results[i]->cell_size*0.65){ sel[i] = SELECTED; selected_num++; continue; } //填涂面积相差达%15,将面积不小于最大点填涂面积的总面积%10的涂点视为填涂 if (maxgraynum - mingraynum>results[i]->cell_size*0.15&&results[i]->gray_num>maxgraynum - results[i]->cell_size*0.1){ sel[i] = SELECTED; selected_num++; continue; } //填涂面积相差达%50,将面积不小于最大点填涂面积的总面积%30的涂点视为填涂 if (maxgraynum - mingraynum>results[i]->cell_size*0.5&&results[i]->gray_num>maxgraynum - results[i]->cell_size*0.3){ sel[i] = SELECTED; selected_num++; continue; } if (maxgraynum - results[i]->gray_num>results[i]->cell_size*0.2){ sel[i] = UNSELECT; unselect_num++; continue; } sel[i] = UNCERTAIN; uncertain_num++; } identify::result::OMR_QUESTION_STATE question_state = identify::result::OMR_QUESTION_STATE::OMR_QUESTION_STATE_NORMAL; if (selected_num>1){ int maxgrayindex = -1; int maxgraynum = -101; for (int i = 0; igray_num - maxgraynum > 100) || (abs(results[i]->gray_num - maxgraynum) <= 100 && results[i]->heidu > results[maxgrayindex]->heidu)) { maxgraynum = results[i]->gray_num; maxgrayindex = i; } } } for (int i = 0; i(avg_gray); anlyseResultTemp.cellNum++; anlyseResultTemp.itemAnalyseResult[i].avg_gray = static_cast(avg_gray); anlyseResultTemp.itemAnalyseResult[i].cell_size = cellSize; anlyseResultTemp.itemAnalyseResult[i].gray_num = grayNum; anlyseResultTemp.itemAnalyseResult[i].heidu = gao_heidu; anlyseResultTemp.itemAnalyseResult[i].mohudu = mo_hu_du; anlyseResultTemp.itemAnalyseResult[i].xiangdui_mianji = refArea; anlyseResultTemp.itemAnalyseResult[i].xiangdui_value = refArea; } anlyseResultTemp.cellAvgGray = anlyseResultTemp.cellNum>0 ? anlyseResultTemp.cellAvgGray / anlyseResultTemp.cellNum : 256; anlyseResultTemp.avg_heidu = topGrayAreaSum>0 ? topGraySum / topGrayAreaSum : 6; if (numTopGray >= int(schemaPage.itemCount / 5)){ anlyseResultTemp.float_heidu = anlyseResultTemp.avg_heidu / schemaPage.user_float_heidu; anlyseResultTemp.benchmarkBlk = schemaPage.worthwhileBlk + anlyseResultTemp.float_heidu; } else{ anlyseResultTemp.benchmarkBlk = numTopGray>0 ? min(6.0, schemaPage.worthwhileBlk + anlyseResultTemp.avg_heidu / schemaPage.user_float_heidu) : 6; anlyseResultTemp.float_heidu = anlyseResultTemp.benchmarkBlk - schemaPage.worthwhileBlk; } if (numTopGray>0){ anlyseResultTemp.avg_heidu = topGrayAreaSum / numTopGray; anlyseResultTemp.float_heidu = anlyseResultTemp.avg_heidu / schemaPage.user_float_heidu; anlyseResultTemp.benchmarkAreaBlk = anlyseResultTemp.float_heidu; } else{ anlyseResultTemp.avg_heidu = 0; anlyseResultTemp.float_heidu = 0; anlyseResultTemp.benchmarkAreaBlk = 0.1; } int r = myanalyseOmrPanoramic(anlyseResultTemp, qs.countNum); r = myGenerateOmrStr(anlyseResultTemp, qs.countNum); return r; } int COnLineCardPageIdentifier::GenerateOmrStr(SchemaPage& schemaPage, string &ret) { char omr_str[512] = { 0 }; //标记是否被选中 SelectType sel[200] = { SelectType::UNSELECT }; for (int groupIndex = 0; groupIndexgray_num > maxgraynum)maxgraynum = results[i]->gray_num; if (results[i]->gray_num < mingraynum)mingraynum = results[i]->gray_num; } int selected_num = 0; int unselect_num = 0; int uncertain_num = 0; for (int i = 0; igray_num>results[i]->cell_size*0.65){ sel[i] = SELECTED; selected_num++; continue; } //填涂面积相差达%20,将面积不小于最大点填涂面积的总面积%10的涂点视为填涂 if (maxgraynum - mingraynum>results[i]->cell_size*0.2&&results[i]->gray_num>maxgraynum - results[i]->cell_size*0.1){ sel[i] = SELECTED; selected_num++; continue; } //填涂面积相差达%50,将面积不小于最大点填涂面积的总面积%30的涂点视为填涂 if (maxgraynum - mingraynum>results[i]->cell_size*0.5&&results[i]->gray_num>maxgraynum - results[i]->cell_size*0.3){ sel[i] = SELECTED; selected_num++; continue; } sel[i] = UNCERTAIN; uncertain_num++; } if (group.omr_out_type == OMR_OUT_TYPE::OMR_OUT_TYPE_SINGLE_NONSTRICT){ if (selected_num > 1){ int maxgrayindex = -1; int maxgraynum = -101; int countSel = 0; for (int i = 0; i < pn; i++) { if (sel[i] == SELECTED) { countSel++; if ((results[i]->gray_num - maxgraynum>100) || (abs(results[i]->gray_num - maxgraynum) <= 100 && results[i]->heidu > results[maxgrayindex]->heidu)) { maxgraynum = results[i]->gray_num; maxgrayindex = i; } } } for (int i = 0; i < pn; i++) { if (sel[i] == SELECTED&&i != maxgrayindex){ sel[i] = UNSELECT; } } } int out_count = 0; for (int i = 0; i < pn; i++) { if (sel[i] == SELECTED){ if (out_count > 0)omr_str[omr_str_len++] = schemaPage.option_spacer; omr_str[omr_str_len++] = items[i]->OutChar; out_count++; } } if (omr_str_len != 1){ return 1; } omr_str[omr_str_len] = '\0'; ret += omr_str; } } return 0; } //读取缺考标记 bool COnLineCardPageIdentifier::ReadQuekaoFlag(SchemaPage &schemaPage, IplImage * dst) { if (schemaPage.quekaoLocatePointIndex.size() < 1) return false; SchemaItem item; item.centerx = schemaPage.quekao.centerx; item.centery = schemaPage.quekao.centery; item.width = schemaPage.quekao.width; item.height = schemaPage.quekao.height; int cellSize, grayNum, char_area_size, char_area_black_count; double refArea, avg_gray, mo_hu_du, gao_heidu, char_area_avg_gray; if (schemaPage.itemCount == 0 && schemaPage.stuQuestionLocatePointIndex.size() < 1) { anlyseResult.backGroundGray = 225; } int ret = caculate_cell_property(schemaPage, item, dst, cellSize, refArea, avg_gray, grayNum, mo_hu_du, gao_heidu, char_area_size, char_area_black_count, char_area_avg_gray); OnlineAnalyseResult anlyseResult; anlyseResult.cellAvgGray += static_cast(avg_gray); anlyseResult.cellNum++; anlyseResult.itemAnalyseResult[0].avg_gray = static_cast(avg_gray); anlyseResult.itemAnalyseResult[0].cell_size = cellSize; anlyseResult.itemAnalyseResult[0].gray_num = grayNum; anlyseResult.itemAnalyseResult[0].heidu = gao_heidu; anlyseResult.itemAnalyseResult[0].mohudu = mo_hu_du; anlyseResult.itemAnalyseResult[0].xiangdui_mianji = refArea; anlyseResult.itemAnalyseResult[0].xiangdui_value = refArea; //标记是否被选中 SelectType sel = UNSELECT; OnlineAnalyseResult::itemResult* results; results = &anlyseResult.itemAnalyseResult[0]; int maxgraynum = -1; int mingraynum = 0xffffff; if (results->gray_num>maxgraynum)maxgraynum = results->gray_num; if (results->gray_numgray_num; //面积超过65% if (results->gray_num>results->cell_size*0.65){ sel = SELECTED; return true; } //填涂面积相差达%20,将面积不小于最大点填涂面积的总面积%10的涂点视为填涂 if (maxgraynum - mingraynum>results->cell_size*0.2&&results->gray_num>maxgraynum - results->cell_size*0.1){ sel = SELECTED; return true; } //填涂面积相差达%50,将面积不小于最大点填涂面积的总面积%30的涂点视为填涂 if (maxgraynum - mingraynum>results->cell_size*0.5&&results->gray_num>maxgraynum - results->cell_size*0.3){ sel = SELECTED; return true; } return false; } void COnLineCardPageIdentifier::DrawSchema(IplImage*dst_img, SchemaPage* & pageSchema) { // 绘制定位点 for (std::size_t i = 0; i < pageSchema->questionLocatePoints.size(); i++){ cvDrawRect(dst_img, cvPoint(pageSchema->questionLocatePoints[i].centerx - pageSchema->questionLocatePoints[i].width / 2.0, pageSchema->questionLocatePoints[i].centery - pageSchema->questionLocatePoints[i].height / 2.0), cvPoint(pageSchema->questionLocatePoints[i].centerx + pageSchema->questionLocatePoints[i].width / 2.0, pageSchema->questionLocatePoints[i].centery + pageSchema->questionLocatePoints[i].height / 2.0), cvScalar(0, 255, 0)); } // 绘制二维码 条形码 for (std::size_t i = 0; i < pageSchema->codes.size(); i++){ cvDrawRect(dst_img, cvPoint(pageSchema->codes[i].centerx - pageSchema->codes[i].width / 2.0, pageSchema->codes[i].centery - pageSchema->codes[i].height / 2.0), cvPoint(pageSchema->codes[i].centerx + pageSchema->codes[i].width / 2.0, pageSchema->codes[i].centery + pageSchema->codes[i].height / 2.0), cvScalar(0, 255, 0)); } // 绘制 for (std::size_t i = 0; i < pageSchema->items.size(); i++){ cvDrawRect(dst_img, cvPoint(pageSchema->items[i].centerx - pageSchema->items[i].width / 2.0, pageSchema->items[i].centery - pageSchema->items[i].height / 2.0), cvPoint(pageSchema->items[i].centerx + pageSchema->items[i].width / 2.0, pageSchema->items[i].centery + pageSchema->items[i].height / 2.0), cvScalar(0, 255, 0)); } // 主观题 for (std::size_t i = 0; i < pageSchema->question_score.size(); i++){ if (pageSchema->question_score[i].scoreBox.bXuanZuoTi){ for (int j = 0; j < pageSchema->question_score[i].countNum; j++){ cvDrawRect(dst_img, cvPoint(pageSchema->question_score[i].item[j].centerx - pageSchema->question_score[i].item[j].width / 2.0, pageSchema->question_score[i].item[j].centery - pageSchema->question_score[i].item[j].height / 2.0), cvPoint(pageSchema->question_score[i].item[j].centerx + pageSchema->question_score[i].item[j].width / 2.0, pageSchema->question_score[i].item[j].centery + pageSchema->question_score[i].item[j].height / 2.0), cvScalar(0, 255, 0)); } } cvDrawRect(dst_img, cvPoint(pageSchema->question_score[i].centerx - pageSchema->question_score[i].width / 2.0, pageSchema->question_score[i].centery - pageSchema->question_score[i].height / 2.0), cvPoint(pageSchema->question_score[i].centerx + pageSchema->question_score[i].width / 2.0, pageSchema->question_score[i].centery + pageSchema->question_score[i].height / 2.0), cvScalar(0, 255, 0)); // 绘制打分区域 int x = pageSchema->question_score[i].scoreBox.pos.x, y = pageSchema->question_score[i].scoreBox.pos.y, w = pageSchema->question_score[i].scoreBox.pos.w, h = pageSchema->question_score[i].scoreBox.pos.h; cvDrawRect(dst_img, cvPoint(x, y), cvPoint(x + w, y + h), cvScalar(255, 0,0)); } // 学号 for (std::size_t i = 0; i < pageSchema->stuItems.size(); i++){ cvDrawRect(dst_img, cvPoint(pageSchema->stuItems[i].centerx - pageSchema->stuItems[i].width / 2.0, pageSchema->stuItems[i].centery - pageSchema->stuItems[i].height / 2.0), cvPoint(pageSchema->stuItems[i].centerx + pageSchema->stuItems[i].width / 2.0, pageSchema->stuItems[i].centery + pageSchema->stuItems[i].height / 2.0), cvScalar(0, 255, 0)); } //缺考标识 if (pageSchema->quekaoLocatePointIndex.size()>0){ cvDrawRect(dst_img, cvPoint(pageSchema->quekao.centerx - pageSchema->quekao.width / 2.0, pageSchema->quekao.centery - pageSchema->quekao.height / 2.0), cvPoint(pageSchema->quekao.centerx + pageSchema->quekao.width / 2.0, pageSchema->quekao.centery + pageSchema->quekao.height / 2.0), cvScalar(0, 0, 255)); } } }