#include "StdAfx.h" #include "ResultReader.h" #include "Affine2DEstimator0.h" #include #include "CrossDetector.h" #include "IdentifyArea.h" std::string g_appFilePathName; namespace identify{ CResultReader::CResultReader(void) { HMODULE module = GetModuleHandle(0); char pFileName[MAX_PATH + 2] = { 0 }; GetModuleFileNameA(module, pFileName, MAX_PATH); std::string strPath = pFileName; int pos = strPath.find_last_of('\\', strPath.length()); g_appFilePathName = strPath.substr(0, pos); strPath = strPath.substr(0, pos) + "\\..\\config.ini"; int nType = GetPrivateProfileIntA("USER", "algorithm_boption", 1, strPath.c_str()); m_nBxuanxiang = (nType == 1); knn = KNearest::create(); } CResultReader::~CResultReader(void) { } inline unsigned char GetGrayFromBGR(const IplImage * img, int x, int y) { #define RGB_GRAY(B,G,R) ((R*38 + G*75 + B*15) >> 7) return RGB_GRAY(CV_IMAGE_ELEM(img, unsigned char, y, x * 3), CV_IMAGE_ELEM(img, unsigned char, y, x * 3 + 1), CV_IMAGE_ELEM(img, unsigned char, y, x * 3 + 2)); } inline unsigned char GetGrayFromGray(const IplImage * img, int x, int y) { return CV_IMAGE_ELEM(img, unsigned char, y, x); } int CResultReader::ReadResult(const IplImage* img, int schemaIndex, cv::Mat transform, double scale, int dir, OMR_RESULT* out_result) { knn->clear(); point_muban.clear(); point_shijuan.clear(); this->omr_result = (OMR_RESULT*)out_result; this->m_pageDirection = dir; m_AffineTransform = transform; m_Scaler0 = scale; SetDefaultOMR_Result(*omr_result); src = (IplImage*)img; if (src == NULL) return -1; if (src->nChannels == 1) _GetGray = &GetGrayFromGray; if (src->nChannels == 3) _GetGray = &GetGrayFromBGR; return ReadResult(schemaIndex); } //绘出识别位置 void DrawIdentify(IplImage * dst_img, OMR_RESULT* omr_result) { cvResetImageROI(dst_img); if (omr_result->identified){ for (int j = 0; j < omr_result->locatepoint_result.size(); j++){ vector& option = omr_result->locatepoint_result; cvDrawRect(dst_img, cvPoint(cvRound(option[j].centerx - option[j].width / 2.0), cvRound(option[j].centery - option[j].height / 2.0)), cvPoint(cvRound(option[j].centerx + option[j].width / 2.0), cvRound(option[j].centery + option[j].height / 2.0)), cvScalar(0, 0, 255)); } for (int i = 0; i < omr_result->group_result.size(); i++) { vector &option = omr_result->group_result[i].option; for (int j = 0; j < option.size(); j++) { cvDrawRect(dst_img, cvPoint(cvRound(option[j].centerx - option[j].width / 2.0), cvRound(option[j].centery - option[j].height / 2.0)), cvPoint(cvRound(option[j].centerx + option[j].width / 2.0), cvRound(option[j].centery + option[j].height / 2.0)), cvScalar(0, 0, 255)); } } } } int CResultReader::ReadResult(int shemaIndex) { const ISCH_SCHEMA_PAGE& schemaPage = (*schemaPages)[shemaIndex]; int ret; //查找辅助定位关系 /************************定位点位置*********************************************/ double fre = getTickFrequency(); int64 t0 = cvGetTickCount(); ret = findAssitLocate(schemaPage); int64 t1 = cvGetTickCount(); double t = (t1 - t0) / fre; if (ret != IDF_SUCCESS) { return ret; } /************************定位点位置*********************************************/ ret = ReadDingWeiDian(schemaPage); if (ret != IDF_SUCCESS) { return ret; } /************************根据给定区域识别二维码*********************************************/ ret = ReadBarCode(schemaPage); if (ret != IDF_SUCCESS) { return ret; } /************************根据给定区域分析填涂项*********************************************/ ret = ReadKeGuanTi(schemaPage); if (ret != IDF_SUCCESS) { return ret; } ret = ReadQuestionScore(schemaPage); if (ret != IDF_SUCCESS) { return ret; } /************************根据给定区域切割图片*********************************************/ ret = ClipImg(schemaPage); if (ret != IDF_SUCCESS) { return ret; } omr_result->card_index = schemaPage.index; omr_result->identified = TRUE; //cvResetImageROI((IplImage*)src); //DrawIdentify((IplImage*)src,omr_result); //char file_name[512]; //sprintf_s(file_name,"%sresult_%05d.png","D:\\img\\",(int)omr_result->phy_card_number); //cvSaveImage(file_name,src); { return IDF_SUCCESS; } } int CResultReader::caculate_cell_property(ISCH_SCHEMA_PAGE& schemaPage, ISCH_SCHEMA_ITEM &item, const 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 & diheidushu) { int gray;//临时变量,灰度值 //int tembackcolor=max((anlyseResult.globalBackGround+200)/2,200); CvRect rr = GetJiaoZhengResultRect(item); int tembackcolor = max(anlyseResult.backGroundGray - 30, 200); int left = int(rr.x); int top = int(rr.y); int right = int(rr.x + rr.width); int bottom = int(rr.y + rr.height); int vtop = (int)(rr.y - rr.height*0.25 + 0.5); /*******************统计字符区域属性************************************/ int cl = left + ((right - left + 1) + 2) / 4; int cr = left + ((right - left + 1) * 3 + 2) / 4; //int ct=top+((bottom-top+1)+2)/4; //int cb=top+((bottom-top+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 = GetGray(dst, x, y); char_area_size++; if (gray < tembackcolor){ char_area_avg_gray += gray; char_area_black_count++; } } } if (char_area_black_count > 0)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 = GetGray(dst, x, y); gray256[gray]++; cellSize++; if (gray < tembackcolor){ avg_gray += gray; grayNum++; } dx = (x - xd)*xRatio; dy = (y - yd)*xRatio; dist = sqrt(dx*dx + dy*dy); gray = max(0, 255 - gray - 32); refArea += gray*(1 - dist); distSum += (1 - dist); } } avg_gray = grayNum > 0 ? 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; i < grayUp; i++) { if (gray256[i] > 0){ 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; diheidushu = 0; for (int i = min(255, tembackcolor - 1); i >= tembackcolor - 45 && i >= 0; i--) { diheidushu += gray256[i]; } int i, endpos, flag = 0; int hui_du_he = 0; int hei_dian_shu = 0; for (i = 0, endpos = grayUp; i < endpos; i++) { if (gray256[i] > 0){ 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 < grayUp&&hei_dian_shu < dianshu_meihaomi*dianshu_meihaomi / 4 + 1 && hei_dian_shu < 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 < grayUp&&pnt_high < dianshu_meihaomi*dianshu_meihaomi / 4 + 1; i++) { pnt_high += gray256[i]; } pos1 = i; pos2 = hei_dian_shu*minRatio >= 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 IDF_DIVIDE_ZERO; } gao_heidu = max(0.0, gao_heidu); 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); mo_hu_du = max(0.0, mo_hu_du); return IDF_SUCCESS; } int CResultReader::ReadKeGuanTi(const ISCH_SCHEMA_PAGE &schemaPage) { if (m_nBxuanxiang){ auto _items = schemaPage.items; if (m_nBxuanxiang == 1 && schemaPage.groups.size() > 0){ try{ auto pGetCVRect = [&](const ISCH_SCHEMA_ITEM* code)->CvRect{ CvRect result_rect; if (code){ result_rect = GetResultRect(*code); } return result_rect; }; std::map> _map_groups_by_type; for (int groupIndex = 0; groupIndex < schemaPage.groups.size(); groupIndex++) { _map_groups_by_type[schemaPage.groups[groupIndex].group_type].push_back(groupIndex); } std::map _map_group; std::vector _vct_release; for (auto it : _map_groups_by_type) { IdentifyArea *ptr_area = new IdentifyArea(it.second.size()); ptr_area->type = static_cast(it.first); _vct_release.push_back(ptr_area); int nIndex = 0; for (auto it_group : it.second) { const ISCH_IDENTIFY_GROUP& group = schemaPage.groups[it_group]; IdentifyGroup*ptr_group = ptr_area->get_group_by_index(nIndex++); _map_group[it_group] = ptr_group; if (ptr_group){ bool mul = true; switch (group.omr_out_type) { case OMR_OUT_TYPE_SINGLE_NONSTRICT_ERROR: case OMR_OUT_TYPE_SINGLE_NONSTRICT: case OMR_OUT_TYPE_SINGLE_STRICT: mul = false; break; case OMR_OUT_TYPE_MUTIL_STRICT: mul = true; break; } ptr_group->init(group.itemCount, std::to_string(group.nID).c_str(), mul); for (int itemindex = 0; itemindex < group.itemCount; itemindex++){ IdentifyItem*ptr_item = ptr_group->get_item_by_index(itemindex); if (ptr_item){ const ISCH_SCHEMA_ITEM*ptr_sc_item = &_items[group.itemIndex[itemindex]]; auto rc = pGetCVRect(ptr_sc_item); ptr_item->x = rc.x; ptr_item->y = rc.y; ptr_item->w = rc.width; ptr_item->h = rc.height; strcpy(ptr_item->name, ptr_sc_item->OutChar); //ptr_item->name[0] = ptr_sc_item->OutChar[0]; } } } } IplImage*dst_gray_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1); cvCvtColor(src, dst_gray_img, CV_BGR2GRAY); try{ if (0 == api_ttpd_analysis_part(cv::cvarrToMat(dst_gray_img), ptr_area)){ } } catch (cv::Exception e){ const char *w = e.what(); int i = 0; ++i; } cvReleaseImage(&dst_gray_img); } omr_result->group_result.resize(schemaPage.groups.size()); identify::result::KEGUANTI_RESULT* ketuanti_result_value = omr_result->group_result.data(); for (int groupIndex = 0; groupIndex < schemaPage.groups.size() && groupIndex < _map_group.size(); groupIndex++) { const ISCH_IDENTIFY_GROUP& group = schemaPage.groups[groupIndex]; bool mul = true; switch (group.omr_out_type) { case OMR_OUT_TYPE_SINGLE_NONSTRICT_ERROR: case OMR_OUT_TYPE_SINGLE_NONSTRICT: case OMR_OUT_TYPE_SINGLE_STRICT: mul = false; if (_map_group[groupIndex]->select_count == _map_group[groupIndex]->item_count) // 单选题如果全选,结果值会保留全部值 { mul = true; } break; case OMR_OUT_TYPE_MUTIL_STRICT: mul = true; break; } std::string omr_str = get_str_by_identify_group(mul ? 1 : 0, _map_group[groupIndex], schemaPage.option_spacer); ketuanti_result_value[groupIndex].answer = omr_str; ketuanti_result_value[groupIndex].question_state = OMR_QUESTION_STATE::OMR_QUESTION_STATE_NORMAL; } for (auto it : _vct_release){ delete it; } _vct_release.clear(); } catch (cv::Exception e){ const char * ss = e.what(); return IDF_FAILURE; } int global_background_color_avg = caculate_global_background(schemaPage); anlyseResult.backGroundGray = global_background_color_avg; return IDF_SUCCESS; } } else{ int global_background_color_avg = caculate_global_background(schemaPage); anlyseResult.backGroundGray = global_background_color_avg; int ret; for (int i = 0; i < schemaPage.items.size(); i++) { ret = caculate_item_property(schemaPage, schemaPage.items[i], src, anlyseResult.itemAnalyseResult[i]); if (ret != IDF_SUCCESS)return ret; } caculate_item_global_property(schemaPage); ret = GenerateOmrStr(schemaPage); } return IDF_SUCCESS; } int CResultReader::GenerateOmrStr(const ISCH_SCHEMA_PAGE& schemaPage) { #define MAX_ITEM 64 #define QQM_ADD 0 // 马百泉 2020.08 针对空白卷未填涂识别错误的修改代码 char omr_str[512]; int omr_str_len = 0; enum SelectType{ //未选中 UNSELECT, //不确定 UNCERTAIN, //选中 SELECTED }; //标记是否被选中 SelectType sel[MAX_ITEM]; SAMPLE_KEGUANTITUDIAN samples[MAX_ITEM]; omr_result->group_result.resize(schemaPage.groups.size()); KEGUANTI_RESULT* ketuanti_result_value = omr_result->group_result.data(); for (int groupIndex = 0; groupIndex < schemaPage.groups.size(); groupIndex++) { omr_str_len = 0; memset(sel, UNSELECT, sizeof(sel)); const ISCH_IDENTIFY_GROUP& group = schemaPage.groups[groupIndex]; int pn = min(MAX_ITEM, group.itemCount); AnalyseResult::itemResult* results[MAX_ITEM]; const ISCH_SCHEMA_ITEM* items[MAX_ITEM]; #if QQM_ADD bool b_multiple = false; // 是否是多项填涂 if (group.omr_out_type == OMR_OUT_TYPE_MUTIL_STRICT) // @林 确认是否正确 b_multiple = true; #endif ketuanti_result_value[groupIndex].option.resize(pn); for (int i = 0; i < pn; i++){ results[i] = &anlyseResult.itemAnalyseResult[group.itemIndex[i]]; items[i] = &schemaPage.items[group.itemIndex[i]]; SaveRect(results[i]->item_position, ketuanti_result_value[groupIndex].option[i]); } int maxgraynum = -1; int second_maxgraynum = -1; int mingraynum = 0xffffff; float max_balck_ref_area = 0; float min_balck_ref_area = 0; for (int i = 0; i < pn; i++) { if (results[i]->gray_num > maxgraynum){ if (maxgraynum > 0){ second_maxgraynum = maxgraynum; }maxgraynum = results[i]->gray_num; max_balck_ref_area = results[i]->gray_num / (float)results[i]->cell_size; } #if QQM_ADD else { if (results[i]->gray_num > second_maxgraynum) { second_maxgraynum = results[i]->gray_num; } } #endif if (results[i]->gray_num < mingraynum){ mingraynum = results[i]->gray_num; min_balck_ref_area = results[i]->gray_num / (float)results[i]->cell_size; } } #if QQM_ADD if (!b_multiple) { for (int i = 0; i < pn; i++) { results[i]->same_group_unselected_gray_num = mingraynum; } } #endif int selected_num = 0; int unselect_num = 0; int uncertain_num = 0; for (int i = 0; i < pn; i++) { //被涂面积小于10% if (results[i]->gray_num < results[i]->cell_size*0.2){ sel[i] = UNSELECT; unselect_num++; continue; } #if QQM_ADD // 小面积的填涂项 小于 0.6直接pass 太**** if (results[i]->cell_size < 700 && results[i]->gray_num < results[i]->cell_size*0.6) { sel[i] = UNSELECT; unselect_num++; continue; } // 填涂面积超过0.8的 直接按填涂处理 怕被下面的误伤 0.8的占比即使是没有填涂图像,也是涂抹之类的 if (results[i]->gray_num > results[i]->cell_size*0.8) { sel[i] = SELECTED; selected_num++; continue; } // 单选填涂面积中填涂的背景区域要超过0.2 & 面积不能太大 目前来说出问题的都是小填涂规格 // 但是 确实也有0.75-0.8之间的填涂,最小的可能超过0.6这时候出错 if (!b_multiple && results[i]->gray_num > results[i]->cell_size*0.6 && results[i]->cell_size < 1200 && results[i]->gray_num < (results[i]->same_group_unselected_gray_num + results[i]->cell_size*0.2)) { if (results[i]->gray_num < (results[i]->same_group_unselected_gray_num + results[i]->cell_size*0.1)) { sel[i] = UNSELECT; unselect_num++; continue; } else { // 前景 0.1 - 0.2的 借用(灰度数-模糊边缘数)的数据再次判断下 float fmin = 1.0; float ri = 0.0; for (int x = 0; x < pn; x++) { float tmp = (results[x]->gray_num - results[x]->mo_hu_bianyu_shu)*1.0 / results[x]->cell_size; if (x == i) { ri = tmp; continue; } if (tmp < fmin) { fmin = tmp; } } if (ri > (fmin + 0.2)) { sel[i] = SELECTED; selected_num++; continue; } else { sel[i] = UNSELECT; unselect_num++; continue; } } } #endif if (results[i]->gray_num < max(results[i]->same_page_unselected_gray_num*1.3, results[i]->same_page_unselected_gray_num + 35.)){ sel[i] = UNSELECT; unselect_num++; continue; } /*if(results[i]->diheidushu>80&&results[i]->diheidushu>results[i]->gray_num*0.45){ sel[i] =UNSELECT; unselect_num++; continue; }*/ //面积超过65% if (results[i]->gray_num > results[i]->cell_size*0.60){ #if QQM_ADD // 还有 占比 0.6-0.7之间的 & 大于最小值+0.2 但是仍然是空白的 只能按照硬规则处理 // 202009.04 英语小填涂项 正常填涂(稍浅色) 0.6-0.7 未填涂0.2-0.3 出错. 添加限制 if (results[i]->gray_num < results[i]->cell_size*0.7 && results[i]->cell_size < 700 && (maxgraynum - second_maxgraynum) < results[i]->cell_size*0.25) { sel[i] = UNSELECT; unselect_num++; continue; } #endif sel[i] = SELECTED; selected_num++; continue; } //填涂面积相差达%50,将面积不小于最大点填涂面积的总面积%20的涂点视为填涂 if (results[i]->gray_num > results[i]->cell_size*0.30&&maxgraynum - mingraynum > results[i]->cell_size*0.5&&results[i]->gray_num > maxgraynum - results[i]->cell_size*0.2){ sel[i] = SELECTED; selected_num++; continue; } //填涂面积相差达%30,将面积不小于最大点填涂面积的总面积%18的涂点视为填涂 if (results[i]->gray_num > results[i]->cell_size*0.30&&maxgraynum - mingraynum > results[i]->cell_size*0.3&&results[i]->gray_num > maxgraynum - results[i]->cell_size*0.28){ sel[i] = SELECTED; selected_num++; continue; } //填涂面积相差达%20,将面积不小于最大点填涂面积的总面积%18的涂点视为填涂 if (results[i]->gray_num > results[i]->cell_size*0.30&&maxgraynum - mingraynum > results[i]->cell_size*0.2&&results[i]->gray_num > maxgraynum - results[i]->cell_size*0.23){ sel[i] = SELECTED; selected_num++; continue; } //if (results[i]->gray_num > results[i]->cell_size*0.40&&results[i]->gray_num > max(results[i]->same_page_unselected_gray_num*1.6, results[i]->same_page_unselected_gray_num + 70.)){ // 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++; } for (int i = 0; i < pn; i++) { if (sel[i] == SELECTED){ if (results[i]->gray_num > results[i]->cell_size*0.7)continue; int not_mo_hu_bianyu_gray_num = results[i]->gray_num - results[i]->mo_hu_bianyu_shu; if (not_mo_hu_bianyu_gray_num < results[i]->cell_size*0.45){ for (int j = 0; j < pn; j++){ if (sel[j] == UNSELECT){ if (results[i]->gray_num < (results[j]->gray_num - results[j]->mo_hu_bianyu_shu)*1.5&¬_mo_hu_bianyu_gray_num < (results[j]->gray_num - results[j]->mo_hu_bianyu_shu)*1.3){ sel[i] = UNSELECT; selected_num--; unselect_num++; break; } if (results[i]->gray_numgray_num*1.2, (double)results[j]->gray_num + 35)){ sel[i] = UNSELECT; selected_num--; unselect_num++; break; } } } } } } if (selected_num<1 && maxgraynum>mingraynum*1.7&&maxgraynum>mingraynum + 100){ for (int i = 0; i < pn; i++) { //面积超过65% if (results[i]->gray_num > results[i]->cell_size*0.35&&results[i]->mohudu<2.0&&results[i]->gray_num>second_maxgraynum*1.4&&results[i]->gray_num > mingraynum*1.6){ sel[i] = SELECTED; selected_num++; continue; } } } // 处理一下填涂后 橡皮擦拭后 干扰的 #if QQM_ADD if (selected_num > 1 && !b_multiple) { int max_gaoheidu_index_ture = 0; // 高黑度.真 for (int i = 0; i < pn; i++) { if (sel[i] == SELECTED) { if (results[i]->gaoheidushu > results[max_gaoheidu_index_ture]->gaoheidushu) max_gaoheidu_index_ture = i; } } for (int i = 0; i < pn; i++) { if (sel[i] == SELECTED) { if (results[i]->gaoheidushu < results[max_gaoheidu_index_ture]->gaoheidushu*0.5) { sel[i] = UNSELECT; selected_num--; unselect_num++; } } } } #endif double max_avg_gray = -1; double min_avg_gray = 99999999999; if (selected_num > 1){ switch (group.omr_out_type){ case OMR_OUT_TYPE_SINGLE_NONSTRICT_ERROR: case OMR_OUT_TYPE_SINGLE_NONSTRICT: case OMR_OUT_TYPE_SINGLE_STRICT: //单选题 int max_gaoheidu_index = 0; for (int i = 0; igray_num - results[i]->diheidushu>results[max_gaoheidu_index]->gray_num - results[max_gaoheidu_index]->diheidushu){ max_gaoheidu_index = i; } } } for (int i = 0; i < pn; i++){ if (sel[i] == SELECTED){ if (results[i]->gray_num - results[i]->diheidushu < results[max_gaoheidu_index]->gray_num*0.62&&results[i]->gray_num - results[i]->diheidushu < results[max_gaoheidu_index]->gray_num - results[max_gaoheidu_index]->diheidushu - 40){ sel[i] = UNSELECT; selected_num--; unselect_num++; } } } for (int i = 0; i < pn; i++){ if (sel[i] == SELECTED && i != max_gaoheidu_index) { sel[i] = UNSELECT; selected_num--; unselect_num++; } } break; } } for (int i = 0; i < pn; i++){ samples[i].BlackRefArea = results[i]->gray_num / (float)results[i]->cell_size; samples[i].HighBlackRefArea = results[i]->gaoheidushu / (float)results[i]->cell_size; samples[i].LowBlackRefArea = results[i]->diheidushu / (float)results[i]->cell_size; samples[i].Blur = (float)results[i]->mohudu; samples[i].RefAvgGray = results[i]->avg_gray; } float maxblackrefarea = 0; float minblackrefarea = 99999; float maxhighblackrefarea = 0; float minrefavggray = 9999; for (int i = 0; i < pn; i++){ if (maxblackrefarea < samples[i].BlackRefArea)maxblackrefarea = samples[i].BlackRefArea; if (minblackrefarea > samples[i].BlackRefArea)minblackrefarea = samples[i].BlackRefArea; if (maxhighblackrefarea < samples[i].HighBlackRefArea)maxhighblackrefarea = samples[i].HighBlackRefArea; float avgGray = (results[i]->gray_num>0 && results[i]->cell_size>0) ? (results[i]->gray_num*results[i]->avg_gray + (results[i]->cell_size - results[i]->gray_num) * 255) / (float)results[i]->cell_size : 255; if (minrefavggray > avgGray)minrefavggray = avgGray; } for (int i = 0; i < pn; i++){ samples[i].MaxBlackRefArea = maxblackrefarea; samples[i].MinBlackRefArea = minblackrefarea; samples[i].MaxHighBlackRefArea = maxhighblackrefarea; samples[i].MinRefAvgGray = minrefavggray; } // //for(int i=0;ipredict(sampleMat,responseMat); // break; // default: // ClassBB::ann_signal->predict(sampleMat,responseMat); // break; // } // float * p = responseMat.ptr(); // for (int m=0;m<9;m++) // { // response+=p[m]; // } // memcpy(ketuanti_result_value[groupIndex].option[i].features,&samples[i],sizeof(float)*9); // /* // int selected=(response>4?SELECTED:UNSELECT); // if(sel[i]!=selected){ // if(sel[i]==SELECTED||selected==SELECTED){ // if(samples[i].BlackRefArea>0.65)sel[i]=SELECTED; // else if(samples[i].BlackRefArea<0.35)sel[i]=UNSELECT; // else sel[i]=(SelectType)selected; // if(samples[i].RefAvgGray>samples[i].MinRefAvgGray+50)sel[i]=UNSELECT; // } // }*/ //} selected_num = 0; for (int i = 0; i < pn; i++){ if (sel[i] == SELECTED){ selected_num++; } } if (selected_num > 1){ float max_not_bianyuan = 0; for (int i = 0; i < pn; i++){ if (sel[i] == SELECTED&&max_not_bianyuan < results[i]->gray_num - results[i]->mo_hu_bianyu_shu){ max_not_bianyuan = results[i]->gray_num - results[i]->mo_hu_bianyu_shu; } } for (int i = 0; i(results[i]->gray_num - results[i]->mo_hu_bianyu_shu) * 2){ sel[i] = UNSELECT; selected_num--; } //if (sel[i] == SELECTED&&max_not_bianyuan > (results[i]->gray_num - results[i]->mo_hu_bianyu_shu)*1.7&&results[i]->gray_num < results[i]->same_page_unselected_gray_num*1.6){ // sel[i] = UNSELECT; // selected_num--; //} } } int omr_out_type = group.omr_out_type; if (selected_num > 1 && (omr_out_type&OTF_SINGLE)){ float min_agv = 999; for (int i = 0; isamples[i].RefAvgGray){ min_agv = samples[i].RefAvgGray; } } for (int i = 0; i < pn; i++){ if (sel[i] == SELECTED&&min_agv < samples[i].RefAvgGray - 25){ sel[i] = UNSELECT; selected_num--; } } } if (selected_num > 1 && (omr_out_type&OTF_MUTIL)){ float min_agv = 999; for (int i = 0; isamples[i].RefAvgGray){ min_agv = samples[i].RefAvgGray; } } for (int i = 0; i < pn; i++){ if (sel[i] == SELECTED&&min_agv < samples[i].RefAvgGray - 50){ sel[i] = UNSELECT; selected_num--; } } } /* if(selected_num<1){ float max_raynum=0; for(int i=0;igray_num)max_raynum=results[i]->gray_num; } int ss_count=0;const int min_threshold =80; int threshold =max(min_threshold ,(int)(results[0]->cell_size*0.2)); for(int i=0;igray_num+threshold)ss_count++; } for(int i=0;ss_count==1&&iresults[i]->gray_num+threshold){sel[i]==SELECTED;selected_num++;} } }*/ int out_count; OMR_QUESTION_STATE question_state = OMR_QUESTION_STATE_NORMAL; switch (group.omr_out_type){ case OMR_OUT_TYPE_SINGLE_NONSTRICT_ERROR: out_count = 0; if (selected_num == 1){ for (int i = 0; i < pn; i++) { if (sel[i] == SELECTED){ if (out_count > 0)omr_str[omr_str_len++] = schemaPage.option_spacer; strcpy(&omr_str[omr_str_len], items[i]->OutChar); omr_str_len += strlen(items[i]->OutChar); out_count++; } } } else if (selected_num > 1){ question_state = OMR_QUESTION_STATE_DUOTU; } else if (selected_num < 1){ question_state = OMR_QUESTION_STATE_LOUTU; } if (out_count == 0){ //omr_str[omr_str_len++]=schemaPage.unselect_char; } break; case OMR_OUT_TYPE_MUTIL_STRICT: case OMR_OUT_TYPE_SINGLE_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; strcpy(&omr_str[omr_str_len], items[i]->OutChar); omr_str_len += strlen(items[i]->OutChar); out_count++; } } if (out_count == 0){ //omr_str[omr_str_len++]=schemaPage.unselect_char; question_state = OMR_QUESTION_STATE_LOUTU; } else if (out_count > 1 && group.omr_out_type == OMR_OUT_TYPE_SINGLE_STRICT){ question_state = OMR_QUESTION_STATE_DUOTU; } break; case OMR_OUT_TYPE_SINGLE_NONSTRICT: if (selected_num > 1){ int maxgrayindex = -1; int maxgraynum = -1; for (int i = 0; igray_num>maxgraynum){ maxgraynum = results[i]->gray_num; maxgrayindex = i; } } for (int i = 0; i < pn; i++) { if (sel[i] == SELECTED&&i != maxgrayindex){ sel[i] = UNSELECT; } } } 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; strcpy(&omr_str[omr_str_len], items[i]->OutChar); omr_str_len += strlen(items[i]->OutChar); out_count++; } } if (out_count == 0){ //omr_str[omr_str_len++]=schemaPage.unselect_char; question_state = OMR_QUESTION_STATE_LOUTU; } break; } omr_str[omr_str_len] = '\0'; ketuanti_result_value[groupIndex].answer = omr_str; ketuanti_result_value[groupIndex].question_state = OMR_QUESTION_STATE::OMR_QUESTION_STATE_NORMAL; } return 0; } int CResultReader::analyseOmrPanoramic(ISCH_SCHEMA_PAGE& 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.items.size(); 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.groups.size()>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.groups.size()]; int cur_item_count;//当前选项的数量 for (int ii=0;iiii){ AnalyseResult::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;mwidth, src->height), src->depth, src->nChannels, src->origin, src->align); cvSetData(&t, src->imageData, src->widthStep); IplImage * dst = &t; int global_background_color_count = 0; int global_background_color_avg = 0; for (int i = 0; i < schemaPage.items.size(); i++) { CvRect result_rect = GetJiaoZhengResultRect(schemaPage.items[i]); int left = int(result_rect.x); int top = int(result_rect.y); int right = int(result_rect.x + result_rect.width); int bottom = int(result_rect.y + result_rect.height); int vtop = (int)(result_rect.y - (result_rect.height + 2) / 4); int vbottom = (int)(result_rect.y + result_rect.height + (result_rect.height + 2) / 4); int background_color_count = 0, background_color_avg = 0; int gray; left = max(0, left); vtop = max(0, vtop); right = min(dst->width - 1, right); vbottom = min(dst->height - 1, vbottom); 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; } unsigned char CResultReader::GetGray(const IplImage * dst, int x, int y) { return _GetGray(dst, x, y); } int CResultReader::ReadBarCode(const ISCH_SCHEMA_PAGE& schemaPage) { #define BARCODE_DEBUG_ENABLE 0 omr_result->qr_result.resize(schemaPage.codes.size()); CODE_RESULT* qr_result_value = omr_result->qr_result.data(); int success_count = 0; int ret; IplImage t; cvInitImageHeader(&t, cvSize(src->width, src->height), src->depth, src->nChannels, src->origin, src->align); cvSetData(&t, src->imageData, src->widthStep); IplImage * img0 = &t; cvResetImageROI(img0); for (int i = 0; i < schemaPage.codes.size(); i++) { const ISCH_SCHEMA_CODE& code = schemaPage.codes[i]; CvRect rect = GetResultRect(code); if ((rect.x + rect.width) > src->width) { rect.x = src->width - rect.width - 1; } if (rect.x<0) { rect.x = 0; } if (rect.y<0) { rect.y = 0; } if (rect.width + rect.x>src->width) { rect.width = src->width - rect.x; } if (rect.height + rect.y>src->height) { rect.height = src->height - rect.y; } SaveRect(rect, qr_result_value[i]); IplImage* img = cvCreateImage(cvSize(rect.width, rect.height), src->depth, src->nChannels); cvSetImageROI(img0, rect); cvCopy(img0, img); //cvSaveImage("D:\\img.jpg", img); /* IplImage* img= cvCreateImage(cvSize(cvRound(code.width),cvRound(code.height)),src->depth,src->nChannels) ; Mat m =m_AffineTransform.clone(); CvMat map_matrix =m; CvPoint2D32f p1 =warpAffinePoint(cvPoint2D32f(0,0),&m_AffineTransform); CvPoint2D32f p2 =warpAffinePoint(cvPoint2D32f(code.centerx,code.centery),&m_AffineTransform); CV_MAT_ELEM(map_matrix,double,0,2)+=(p2.x-p1.x); CV_MAT_ELEM(map_matrix,double,1,2)+=(p2.y-p1.y); cvGetQuadrangleSubPix(src,img,&map_matrix); cvShowImage("img",img); cvWaitKey(0); */ std::string result; //ret = PraseBarCode(img, result); { cv::Mat matDstGray = cvarrToMat(img); char szRes[1024]; ret = api_parse_barcode_qrcode(matDstGray, CODE_BAR, szRes, 1024); result = szRes; } // result = std::string(result, 1, result.size()); cvReleaseImage(&img); if (ret == IDF_SUCCESS){ qr_result_value[i].qr_str = result; omr_result->card_qrFlag = 1; success_count++; } else{ omr_result->card_qrFlag = -1; qr_result_value[i].qr_str = ""; } } return IDF_SUCCESS; } void CResultReader::SetDefaultOMR_Result(OMR_RESULT& omr_result) { omr_result.logic_page_number = -1; omr_result.identified = FALSE; omr_result.identify_msg = "没有匹配的模板"; omr_result.time = 0; omr_result.card_index = -1; omr_result.card_qrFlag = 0; omr_result.card_name[0] = '\0'; } int CResultReader::ClipImg(const ISCH_SCHEMA_PAGE& schemaPage) { IplImage t; cvInitImageHeader(&t, cvSize(src->width, src->height), src->depth, src->nChannels, src->origin, src->align); cvSetData(&t, src->imageData, src->widthStep); IplImage * img0 = &t; cvResetImageROI(img0); omr_result->cut_area_result.resize(schemaPage.cutAreas.size()); CUT_AREA_RESULT* cut_area_result_value = omr_result->cut_area_result.data(); for (int i = 0; i < schemaPage.cutAreas.size(); i++) { const ISCH_SCHEMA_CLIP& cutArea = schemaPage.cutAreas[i]; CvRect rect = cvRect(cutArea.centerx - cutArea.width / 2, cutArea.centery - cutArea.height / 2, cutArea.width, cutArea.height); SaveRect(rect, cut_area_result_value[i]); const double scale = 3 / 3.0; IplImage* img = cvCreateImage(cvSize(cvRound(cutArea.width*scale), cvRound(cutArea.height*scale)), src->depth, src->nChannels); Mat m = m_AffineTransform.clone(); CvMat map_matrix = m; CvPoint2D32f p1 = warpAffinePoint(cvPoint2D32f(0, 0), &m); CvPoint2D32f p2 = warpAffinePoint(cvPoint2D32f(cutArea.centerx, cutArea.centery), &m); CV_MAT_ELEM(map_matrix, double, 0, 0) /= scale; CV_MAT_ELEM(map_matrix, double, 0, 1) /= scale; CV_MAT_ELEM(map_matrix, double, 1, 0) /= scale; CV_MAT_ELEM(map_matrix, double, 1, 1) /= scale; CV_MAT_ELEM(map_matrix, double, 0, 2) += (p2.x - p1.x); CV_MAT_ELEM(map_matrix, double, 1, 2) += (p2.y - p1.y); cvGetQuadrangleSubPix(img0, img, &map_matrix); if (img->nChannels == 3){ IplImage * temp = cvCreateImage(cvSize(img->width, img->height), IPL_DEPTH_8U, 1); cvCvtColor(img, temp, CV_BGR2GRAY); cvReleaseImage(&img); img = temp; } vector dst; //cv::Mat _img(img); cv::Mat _img = cv::cvarrToMat(img); /*直方图拉伸增强图像*/ cv::Mat hist; vector range; range.push_back(0); range.push_back(255); calcHist(vector(1, _img), vector(1, 0), Mat(), hist, vector(1, 256), range); int type = hist.type(); double sum_low = 0; double sum_low2 = 0; double sum_high = 0; double sum_high2 = 0; double imin = 0, imax = 255; for (int idx_i = 0; idx_i < 128; idx_i++) { sum_low += hist.at(idx_i, 0); } sum_low *= 0.5; for (int idx_i = 0; idx_i < 128; idx_i++) { sum_low2 += hist.at(idx_i, 0); if (sum_low < sum_low2){ imin = idx_i; break; } } for (int idx_i = 255; idx_i > 220; idx_i--) { sum_high += hist.at(idx_i, 0); } sum_high *= 0.8; for (int idx_i = 255; idx_i > 220; idx_i--) { sum_high2 += hist.at(idx_i, 0); if (sum_high < sum_high2){ imax = idx_i; break; } } Mat lookup(1, 256, CV_8U); for (int idx_i = 0; idx_i < imin; idx_i++) { lookup.at(idx_i) = 0; } for (int idx_i = imin; idx_i <= imax; idx_i++) { lookup.at(idx_i) = static_cast(255 * (idx_i - imin) / (imax - imin) + 0.5); } for (int idx_i = imax + 1; idx_i < 256; idx_i++) { lookup.at(idx_i) = 255; } cv::LUT(_img, lookup, _img); /*保存图像*/ imencode(".png", _img, dst); cut_area_result_value[i].obj_id = cutArea.nID; cut_area_result_value[i].centerx = cutArea.centerx; cut_area_result_value[i].centery = cutArea.centery; cut_area_result_value[i].width = img->width; cut_area_result_value[i].height = img->height; cut_area_result_value[i].area_name = cutArea.area_name_by_questionNo; cut_area_result_value[i].area_index = cutArea.markUnit; cut_area_result_value[i].area_sub_index = cutArea.markUnitPart; cut_area_result_value[i].img_data = dst; cvReleaseImage(&img); } return IDF_SUCCESS; } void CResultReader::SetSchemaPages(boost::shared_ptrschema) { this->schemaPages = schema; } template T2 CResultReader::warpAffinePoint(T1& src, Mat * map_matrix) { T2 r; r.x = map_matrix->at(0, 0)*src.x + map_matrix->at(0, 1)*src.y + map_matrix->at(0, 2); r.y = map_matrix->at(1, 0)*src.x + map_matrix->at(1, 1)*src.y + map_matrix->at(1, 2); return r; } template CvRect CResultReader::GetResultRect(T1& item) { CvRect r; CvPoint2D32f p = warpAffinePoint(cvPoint2D32f(item.centerx, item.centery), &m_AffineTransform); if (m_pageDirection &(ROTATION_0 | ROTATION_180)){ r.width = cvRound(item.width*m_Scaler0); r.height = cvRound(item.height*m_Scaler0); } else{ r.height = cvRound(item.width*m_Scaler0); r.width = cvRound(item.height*m_Scaler0); } r.x = cvRound(p.x - r.width / 2.0); r.y = cvRound(p.y - r.height / 2.0); return r; } template CvRect CResultReader::GetJiaoZhengResultRect(T1& item) { CvRect r; CvPoint2D32f p = GetJiaoZhengResultPoint(cvPoint2D32f(item.centerx, item.centery)); if (m_pageDirection &(ROTATION_0 | ROTATION_180)){ r.width = cvRound(item.width*m_Scaler0); r.height = cvRound(item.height*m_Scaler0); } else{ r.height = cvRound(item.width*m_Scaler0); r.width = cvRound(item.height*m_Scaler0); } r.x = cvRound(p.x - r.width / 2.0); r.y = cvRound(p.y - r.height / 2.0); return r; } template void CResultReader::SaveRect(CvRect& rect, T& result) { result.centerx = rect.x + rect.width / 2.0; result.centery = rect.y + rect.height / 2.0; result.width = rect.width; result.height = rect.height; result.angle = 0; } int CResultReader::ReadDingWeiDian(const ISCH_SCHEMA_PAGE& schemaPage) { #define BARCODE_DEBUG_ENABLE 0 omr_result->locatepoint_result.resize(schemaPage.locatePoints.size()); LOCATE_POINT_RESULT* locatepoint_result_value = omr_result->locatepoint_result.data(); for (int i = 0; i < schemaPage.locatePoints.size(); i++) { const ISCH_SCHEMA_LOCATE_POINT& code = schemaPage.locatePoints[i]; CvRect rect = GetResultRect(code); SaveRect(rect, locatepoint_result_value[i]); } return IDF_SUCCESS; } int CResultReader::caculate_item_property(const ISCH_SCHEMA_PAGE& schemaPage, const ISCH_SCHEMA_ITEM &item, const IplImage * dst0, AnalyseResult::itemResult& item_result) { IplImage t; cvInitImageHeader(&t, cvSize(dst0->width, dst0->height), dst0->depth, dst0->nChannels, dst0->origin, dst0->align); cvSetData(&t, dst0->imageData, dst0->widthStep); IplImage * dst = &t; int gray; CvRect item_roi = GetJiaoZhengResultRect(item); if (item_roi.x<0 || item_roi.y<0 || item_roi.x + item_roi.width>src->width || item_roi.y + item_roi.height>src->height)return IDF_FAILURE; int tembackcolor = max(anlyseResult.backGroundGray - 30, 200); GetCorrectedRect(item_roi, src, tembackcolor); item_result.item_position = item_roi; //模糊边缘点数 int mo_hu_bianyu_shu = 0; for (int y = item_roi.y, endy = item_roi.y + item_roi.height; y < endy; y++) { for (int x = item_roi.x, endx = item_roi.x + item_roi.width; x < endx; x++) { int gray = GetGray(dst, x, y); if (gray <= 128)continue; if (gray >= tembackcolor)continue; int sxx = min(dst->width - 1, max(0, x - 2)); int exx = min(dst->width - 1, max(0, x + 2)); int syy = min(dst->height - 1, max(0, y - 2)); int eyy = min(dst->height - 1, max(0, y + 2)); int gray_thresold = gray - 70; //标记当前点是否是模糊的边缘点 bool ismohubianyuandian = false; for (int yy = syy; !ismohubianyuandian&&yy <= eyy; yy++) { for (int xx = sxx; !ismohubianyuandian&&xx <= exx; xx++) { if (GetGray(dst, xx, yy) < gray_thresold){ ismohubianyuandian = true; break; } } } if (ismohubianyuandian)mo_hu_bianyu_shu++; } } int left = int(item_roi.x); int top = int(item_roi.y); int right = int(item_roi.x + item_roi.width); int bottom = int(item_roi.y + item_roi.height); //灰度直方图 int gray256[260]; memset(gray256, 0, sizeof(gray256)); for (int y = top; y <= bottom; y++) { for (int x = left; x <= right; x++) { gray = GetGray(dst, x, y); gray256[gray]++; } } int cellSize = (right - left + 1)*(bottom - top + 1); int idx_first = 0; for (int idx_gray = 0; idx_gray < 256; idx_gray++) { if (gray256[idx_gray] > 0){ idx_first = idx_gray; break; } } int sum_gray = 0; int gray_num = 0; for (int idx_gray = idx_first; idx_gray < tembackcolor&&idx_gray<256; idx_gray++) { gray_num += gray256[idx_gray]; sum_gray += (idx_gray*gray256[idx_gray]); } float avg_gray = gray_num > 0 ? sum_gray / (float)gray_num : 255; int diheidushu = 0; for (int idx_gray = tembackcolor - 1; idx_gray > tembackcolor - 40 && idx_gray > 128; idx_gray--) { diheidushu += gray256[idx_gray]; } int gaoheidushu = 0; for (int idx_gray = idx_first, end = idx_first + 40; idx_gray < tembackcolor&&idx_gray < end; idx_gray++) { gaoheidushu += gray256[idx_gray]; } int midheidushu = max(0, gray_num - gaoheidushu - diheidushu); double mo_hu_du = ((diheidushu + midheidushu) / (double)gaoheidushu + diheidushu / (double)(gaoheidushu + midheidushu)) / 2.0; mo_hu_du = std::min(std::max(0.0, mo_hu_du), 5.0); item_result.mo_hu_bianyu_shu = mo_hu_bianyu_shu; item_result.gray_num = gray_num; item_result.diheidushu = diheidushu; item_result.gaoheidushu = gaoheidushu; item_result.mohudu = mo_hu_du; item_result.avg_gray = avg_gray; item_result.cell_size = cellSize; item_result.xiangdui_mianji = gray_num / (double)cellSize; return IDF_SUCCESS; } bool sort_item_by_xiangdui_mianji(AnalyseResult::itemResult*item1, AnalyseResult::itemResult*item2){ return item1->xiangdui_mianji < item2->xiangdui_mianji; } void CResultReader::caculate_item_global_property(const ISCH_SCHEMA_PAGE & schemaPage) { vector items; int item_count = schemaPage.items.size(); for (int idx_item = 0; idx_item < item_count; idx_item++){ items.push_back(&anlyseResult.itemAnalyseResult[idx_item]); } std::sort(items.begin(), items.end(), sort_item_by_xiangdui_mianji); if (items.size() >= 2 && items[0]->xiangdui_mianji < 0.6&&items[0]->xiangdui_mianji*1.5 < items[items.size() - 1]->xiangdui_mianji){ double sum_xiangdu_mianji = 0; int xiangdui_mianji_count = 0; double max_xiangduimianji = (items[items.size() - 1]->xiangdui_mianji - items[0]->xiangdui_mianji) / 3 + items[0]->xiangdui_mianji; for (int idx_item = 0; idx_item < item_count&&items[idx_item]->xiangdui_mianji < max_xiangduimianji; idx_item++){ sum_xiangdu_mianji += items[idx_item]->xiangdui_mianji; xiangdui_mianji_count++; } for (int idx_item = 0; idx_item < item_count; idx_item++){ items[idx_item]->same_page_unselected_gray_num = items[idx_item]->cell_size*(sum_xiangdu_mianji / xiangdui_mianji_count); } } else { for (int idx_item = 0; idx_item < item_count; idx_item++){ items[idx_item]->same_page_unselected_gray_num = items[idx_item]->cell_size*0.35; } } } bool sort_key_point_by_response(const KeyPoint& k1, const KeyPoint& k2){ return k1.response > k2.response; } int CResultReader::findAssitLocate(const ISCH_SCHEMA_PAGE& schemaPage) { IplImage t; cvInitImageHeader(&t, cvSize(src->width, src->height), src->depth, src->nChannels, src->origin, src->align); cvSetData(&t, src->imageData, src->widthStep); IplImage * img = &t; for (int i = 0; i < schemaPage.assistLocateArea.size(); i++) { cvResetImageROI(img); int left, top, right, bottom; const ISCH_SCHEMA_LOCATE_AREA& locateArea = schemaPage.assistLocateArea[i].locate_area; const vector& locateAreaKeys = schemaPage.assistLocateArea[i].locateAreasKeyPoints; const CvPoint locateAreaOffset = schemaPage.assistLocateArea[i].locateAreasOffset; const Mat& locateAreaDescriptor = schemaPage.assistLocateArea[i].locateAreasDescriptor; if (locateAreaDescriptor.rows < 1)continue; const int ww0 = 100; const int hh0 = 100; double tw = locateArea.width + ww0, th = locateArea.height + hh0; CvRect rect = GetResultRect(locateArea); left = std::max(0.0, std::min((double)img->width - 1, rect.x + (rect.width - tw) / 2)); right = std::max(0.0, std::min((double)img->width - 1, rect.x + (rect.width + tw) / 2)); top = std::max(0.0, std::min((double)img->height - 1, rect.y + (rect.height - th) / 2)); bottom = std::max(0.0, std::min((double)img->height - 1, rect.y + (rect.height + th) / 2)); cvSetImageROI(img, cvRect(left, top, right - left + 1, bottom - top + 1)); IplImage * grayImg = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1); int64 t0 = cvGetTickCount(); cvCvtColor(img, grayImg, CV_BGR2GRAY); int64 t01 = cvGetTickCount(); cvSmooth(grayImg, grayImg, CV_GAUSSIAN, 5); Mat m_m = cv::cvarrToMat(grayImg, false); std::vector keyPoints; Mat descriptor; int64 t1 = cvGetTickCount(); PtrpDetector = SurfFeatureDetector::create();// 这里我们用了SURF特征点 cv::Mat mask = cv::Mat::zeros(m_m.rows, m_m.cols, CV_8U); const int ww = 100; const int ww_2 = (ww0 - ww) / 2; const int hh = 100; const int hh_2 = (hh0 - hh) / 2; mask(cvRect(ww_2, hh_2, ww, hh)).setTo(cv::Scalar(1)); mask(cvRect(mask.cols - ww - ww_2, hh_2, ww, hh)).setTo(cv::Scalar(1)); mask(cvRect(ww_2, mask.rows - hh0 - hh_2, ww, hh)).setTo(cv::Scalar(1)); mask(cvRect(mask.cols - ww - ww_2, mask.rows - hh0 - hh_2, ww, hh)).setTo(cv::Scalar(1)); mask(cvRect((mask.cols - ww) / 2, (mask.rows - hh) / 2, ww, hh)).setTo(cv::Scalar(1)); pDetector->detect(m_m, keyPoints, mask); /*std::sort(keyPoints.begin(),keyPoints.end(),sort_key_point_by_response); int size =std::max(min((int)keyPoints.size(),50),std::min(200,(int)keyPoints.size()*2/3)); keyPoints.resize(size);*/ int64 t2 = cvGetTickCount(); PtrpExtractor = SurfDescriptorExtractor::create(); // 提取SURF描述向量 pExtractor->compute(m_m, keyPoints, descriptor); int64 t3 = cvGetTickCount(); vector Matches; PtrpMatcher = new FlannBasedMatcher(); // 使用Flann匹配算法 int64 t3_1 = cvGetTickCount(); if (descriptor.rows > 0 && locateAreaDescriptor.rows > 0)pMatcher->match(descriptor, locateAreaDescriptor, Matches); int64 t4 = cvGetTickCount(); if (Matches.size() >= 3){ vector _from; vector _to; for (int n = 0; n < Matches.size(); n++) { Point2f to0 = warpAffinePoint(Point2f(locateAreaKeys[Matches[n].trainIdx].pt.x + locateAreaOffset.x, locateAreaKeys[Matches[n].trainIdx].pt.x + locateAreaOffset.y), &m_AffineTransform); Point2f to1 = Point2f(keyPoints[Matches[n].queryIdx].pt.x + left, keyPoints[Matches[n].queryIdx].pt.x + top); if (((to0.x - to1.x)*(to0.x - to1.x) + (to0.y - to1.y)*(to0.y - to1.y))>35 * 35)continue; _to.push_back(keyPoints[Matches[n].queryIdx].pt); _from.push_back(locateAreaKeys[Matches[n].trainIdx].pt); } if (_from.size() >= 3){ // Show result Mat _out; Mat _inliers; int64 t5 = cvGetTickCount(); int su = estimateAffine2D0(_from, _to, _out, _inliers, 2); int64 t6 = cvGetTickCount(); double tickFre = getTickFrequency(); double tt[] = { (t01 - t0) / tickFre, (t1 - t01) / tickFre, (t2 - t1) / tickFre, (t3 - t2) / tickFre, (t3_1 - t3) / tickFre, (t4 - t3_1) / tickFre, (t5 - t4) / tickFre, (t6 - t5) / tickFre, (t6 - t0) / tickFre }; if (su > cv::max(5.0, _from.size()*0.1)) { Point2f src[] = { Point2f(0, 0), Point2f(1000, 0), Point2f(0, 1000), Point2f(1000, 1000) }; Point2f dst[] = { warpAffinePoint(src[0], &_out), warpAffinePoint(src[1], &_out), warpAffinePoint(src[2], &_out), warpAffinePoint(src[3], &_out) }; double d_src[] = { GetDistance(src[0], src[1]), GetDistance(src[0], src[2]), GetDistance(src[1], src[2]), GetDistance(src[0], src[3]) }; double d_dst[] = { GetDistance(dst[0], dst[1]), GetDistance(dst[0], dst[2]), GetDistance(dst[1], dst[2]), GetDistance(dst[0], dst[3]) }; double scales[] = { d_dst[0] / d_src[0], d_dst[1] / d_src[1], d_dst[2] / d_src[2], d_dst[3] / d_src[3] }; double scale = 0; for (int idx_s_i = 0, length_s = sizeof(scales) / sizeof(scales[0]); idx_s_i < length_s; idx_s_i++) { for (int idx_s_j = idx_s_i + 1; idx_s_j < length_s; idx_s_j++) { scale = max(scale, abs(scales[idx_s_i] - scales[idx_s_j])); } } double d_duijiaoxian = abs(d_dst[2] / d_src[3] * d_dst[3] - d_dst[2]); if (scale < 0.09&&d_duijiaoxian < 100){//变形过大 double centerx0 = locateArea.centerx; double centery0 = locateArea.centery; double centerx1 = locateArea.centerx - locateAreaOffset.x; double centery1 = locateArea.centery - locateAreaOffset.y; Point2f point_src0[] = { Point2f(centerx0, centery0), Point2f(centerx0 - 100, centery0 - 100), Point2f(centerx0 - 100, centery0 + 100), Point2f(centerx0 + 100, centery0 - 100), Point2f(centerx0 + 100, centery0 + 100) }; Point2f point_src1[] = { Point2f(centerx1, centery1), Point2f(centerx1 - 100, centery1 - 100), Point2f(centerx1 - 100, centery1 + 100), Point2f(centerx1 + 100, centery1 - 100), Point2f(centerx1 + 100, centery1 + 100) }; double dist[5]; bool is_all_less_thresold = true; const double thresold = 20; for (int idx_dist = 0; idx_dist < 5; idx_dist++) { Point2f point_dst0 = warpAffinePoint(point_src0[idx_dist], &m_AffineTransform); Point2f point_dst1 = warpAffinePoint(point_src1[idx_dist], &_out); double dx = point_dst1.x + left - point_dst0.x; double dy = point_dst1.y + top - point_dst0.y; dist[idx_dist] = sqrt(dx*dx + dy*dy); if (dist[idx_dist] >= thresold){ is_all_less_thresold = false; break; } } if (is_all_less_thresold){ for (float x = locateArea.centerx - locateArea.width / 2.0 - locateAreaOffset.x, endx = locateArea.centerx + locateArea.width / 2.0 - locateAreaOffset.x; x < endx; x += 10) { for (float y = locateArea.centery - locateArea.height / 2.0 - locateAreaOffset.y, endy = locateArea.centery + locateArea.height / 2.0 - locateAreaOffset.y; y < endy; y += 10) { Point2f dst = warpAffinePoint(Point2f(x, y), &_out); point_muban.push_back(Point2f(locateAreaOffset.x + x, locateAreaOffset.y + y)); point_shijuan.push_back(Point2f(left + dst.x, top + dst.y)); } } } } } } } cvReleaseImage(&grayImg); } if (point_muban.size() > 0){ cv::Mat response(point_muban.size(), 1, CV_32F); cv::Mat trainData(point_muban.size(), 2, CV_32F); for (int i = 0; i < point_muban.size(); i++) { trainData.at(i, 0) = point_muban[i].x; trainData.at(i, 1) = point_muban[i].y; response.at(i, 0) = i; } Ptr traind = cv::ml::TrainData::create(trainData, ROW_SAMPLE, response); knn->train(traind); } return IDF_SUCCESS; } void CResultReader::GetCorrectedRect(CvRect &rr, const IplImage * src, int tembackcolor) { IplImage t; cvInitImageHeader(&t, cvSize(src->width, src->height), src->depth, src->nChannels, src->origin, src->align); cvSetData(&t, src->imageData, src->widthStep); IplImage * dst = &t; const int detect_size = 3; int w = rr.width; int h = rr.height; int detect_src_left = max(0, rr.x - detect_size); int detect_src_top = max(0, rr.y - detect_size); int detect_src_right = min(dst->width - 1, rr.x + w + detect_size * 2 - 1); int detect_src_bottom = min(dst->height - 1, rr.y + h + detect_size * 2 - 1); int detect_w = detect_src_right - detect_src_left + 1; int detect_h = detect_src_bottom - detect_src_top + 1; IplImage * timg = cvCreateImage(cvSize(detect_w, detect_h), IPL_DEPTH_8U, 1); cvSetImageROI(dst, cvRect(detect_src_left, detect_src_top, detect_w, detect_h)); if (dst->nChannels == 3){ cvCvtColor(dst, timg, CV_BGR2GRAY); cvThreshold(timg, timg, tembackcolor, 1, CV_THRESH_BINARY_INV); } else{ cvThreshold(dst, timg, tembackcolor, 1, CV_THRESH_BINARY_INV); } IplImage * iter = cvCreateImage(cvSize(detect_w + 1, detect_h + 1), IPL_DEPTH_32S, 1); cvIntegral(timg, iter); int max_gray_count = -1; CvRect max_gray_count_rect; for (int xx = detect_src_left - rr.x; xx <= detect_src_right - (rr.x + rr.width - 1); xx++) { for (int yy = detect_src_top - rr.y; yy <= detect_src_bottom - (rr.y + rr.height - 1); yy++) { int iter_left = max(0, detect_size + xx); int iter_right = min(rr.width + detect_size * 2, detect_size + xx + rr.width); int iter_top = max(0, detect_size + yy); int iter_bottom = min(rr.height + detect_size * 2, detect_size + yy + rr.height); int gray_count = CV_IMAGE_ELEM(iter, int, iter_bottom, iter_right) - CV_IMAGE_ELEM(iter, int, iter_top, iter_right) - CV_IMAGE_ELEM(iter, int, iter_bottom, iter_left) + CV_IMAGE_ELEM(iter, int, iter_top, iter_left); if (gray_count > max_gray_count){ max_gray_count = gray_count; max_gray_count_rect = cvRect(rr.x + xx, rr.y + yy, rr.width, rr.height); } } } if (max_gray_count > 0){ rr = max_gray_count_rect; } cvReleaseImage(&timg); cvReleaseImage(&iter); } template T2 CResultReader::GetJiaoZhengResultPoint(T1& point) { float data[] = { point.x, point.y }; T2 resultPoint; cv::Mat samples(1, 2, CV_32F, data); cv::Mat results; cv::Mat nresponse; cv::Mat dist; if (knn->isTrained()){ float response = knn->findNearest(samples, 1, results, nresponse, dist); int idx = response; if (0 <= idx&&idx < point_shijuan.size()){ cv::Point2f pm = point_muban[idx]; if (GetDistance(pm, point) < 50){ cv::Point2f ps0 = warpAffinePoint(pm, &m_AffineTransform); cv::Point2f ps1 = point_shijuan[idx]; float dx = ps1.x - ps0.x; float dy = ps1.y - ps0.y; cv::Point2f ps0_0 = warpAffinePoint(Point2f(point.x, point.y), &m_AffineTransform); resultPoint.x = ps0_0.x + dx; resultPoint.y = ps0_0.y + dy; } else{ resultPoint = warpAffinePoint(Point2f(point.x, point.y), &m_AffineTransform); } } else{ resultPoint = warpAffinePoint(Point2f(point.x, point.y), &m_AffineTransform); } } else{ resultPoint = warpAffinePoint(Point2f(point.x, point.y), &m_AffineTransform); } return resultPoint; } int CResultReader::ReadQuestionScore(const ISCH_SCHEMA_PAGE &schemaPage) { IplImage t; cvInitImageHeader(&t, cvSize(src->width, src->height), src->depth, src->nChannels, src->origin, src->align); cvSetData(&t, src->imageData, src->widthStep); IplImage * dst = &t; omr_result->zhutuanti_result.resize(schemaPage.zhuguantis.size()); vector & zhutuanti_result_value = omr_result->zhutuanti_result; for (int i = 0, score_count=0; i < schemaPage.zhuguantis.size(); i++){ const ISCH_SCHEMA_ZHUGUANTI& qs = schemaPage.zhuguantis[i]; double pscale = m_Scaler0; int redcount[30]; int red_in_count[30]; float w = qs.width*pscale / qs.options.size(); float h = qs.height*pscale; float dy = 0;// (ry - ly) / (float)qs.count; BOOL hasSelect = FALSE; double lx = m_AffineTransform.at(0, 0)*(qs.centerx - qs.width / 2) + m_AffineTransform.at(0, 1)*(qs.centery - qs.height / 2) + m_AffineTransform.at(0, 2); double rx = m_AffineTransform.at(0, 0)*(qs.centerx + qs.width / 2) + m_AffineTransform.at(0, 1)*(qs.centery + qs.height / 2) + m_AffineTransform.at(0, 2); int detect_l = lx; int detect_r = rx; double ly = m_AffineTransform.at(1, 0)*(qs.centerx - qs.width / 2) + m_AffineTransform.at(1, 1)*(qs.centery - qs.height / 2) + m_AffineTransform.at(1, 2); int detect_t = max(0, int(ly - h / 2 - 1)); int detect_b = min(dst->height - 1, int(ly + 3 * h / 2 - 1)); CvRect detect_rect = cvRect(detect_l, detect_t, detect_r - detect_l + 1, detect_b - detect_t + 1); CvRect normal_rect = cvRect(lx, ly, rx - lx + 1, h); GetZhuGuanTiRedCount(dst, cvRect(detect_l, detect_t, detect_r - detect_l + 1, detect_b - detect_t + 1), normal_rect, redcount, red_in_count, qs.options.size()); zhutuanti_result_value[score_count].option.resize(qs.options.size()); for (int j = 0; j < qs.options.size(); j++){ CvRect rect = cvRect(detect_r - (j + 1)*(detect_r - detect_l + 1) / qs.options.size(), detect_t, (detect_r - detect_l + 1) / qs.options.size(), detect_b - detect_t + 1); SaveRect(rect, zhutuanti_result_value[score_count].option[j]); } float score = 0; BOOL bx = FALSE;//是否判分小数位 BOOL bg = FALSE;//是否判分个位 BOOL bs = FALSE;//是否判分十位 { //小数位 int red_area = 0; int red_area_index = -1; int red_area_index0 = -1; for (int m = 0, n = 0; m < 1; m++, n++) { if (red_in_count[n] > red_area){ red_area = red_in_count[n]; red_area_index = m; red_area_index0 = n; } } if (red_area_index >= 0 && redcount[red_area_index0] > 25){ score = score + 0.5*(red_area_index + 1); bx = TRUE; } } { //个位 int red_area = 0; int red_area_index = -1; int red_area_index0 = -1; for (int m = 0, n = 2; m < 10 && n < qs.valid_option_count; m++, n++) { if (red_in_count[n] > red_area){ red_area = red_in_count[n]; red_area_index = m; red_area_index0 = n; } } if (red_area_index >= 0 && redcount[red_area_index0] > 25){ score = score + 1 * (red_area_index); bg = TRUE; } } { //十位 int red_area = 0; int red_area_index = -1; int red_area_index0 = -1; for (int m = 0, n = 13; m < 9 && n < qs.valid_option_count; m++, n++) { if (red_in_count[n] > red_area){ red_area = red_in_count[n]; red_area_index = m; red_area_index0 = n; } } if (red_area_index >= 0 && redcount[red_area_index0] > 25){ score = score + 10 * (red_area_index + 1); bs = TRUE; } } zhutuanti_result_value[score_count].question_score = score; zhutuanti_result_value[score_count].question_state = (bx || bg || bs) ? OMR_QUESTION_STATE_NORMAL : OMR_QUESTION_STATE_LOUPI; //zhutuanti_result_value[score_count].question_index = qs.question_index; zhutuanti_result_value[score_count].question_code = qs.question_code; zhutuanti_result_value[score_count].maxscore = 0; zhutuanti_result_value[score_count].omr_question_type = ZHUTUANTI; score_count++; } omr_result->tiankongti_result.resize(schemaPage.tiankongtis.size()); vector & tiankongti_result_value = omr_result->tiankongti_result; for (int i = 0, tiankong_count = 0; i < schemaPage.tiankongtis.size(); i++){ const ISCH_SCHEMA_TIANKONGTI& qs = schemaPage.tiankongtis[i]; double pscale = m_Scaler0; float w = qs.width*pscale; float h = qs.height*pscale; double rx = m_AffineTransform.at(0, 0)*(qs.centerx + qs.width / 2) + m_AffineTransform.at(0, 1)*(qs.centery + qs.height / 2) + m_AffineTransform.at(0, 2); double ly = m_AffineTransform.at(1, 0)*(qs.centerx - qs.width / 2) + m_AffineTransform.at(1, 1)*(qs.centery - qs.height / 2) + m_AffineTransform.at(1, 2); for (int j = 0; j < 1; j++){ CvRect rect = cvRect((int)(rx - (j + 1)*w - 3), (int)(ly - 3), (int)(w + 6), (int)(h + 6)); SaveRect(rect, tiankongti_result_value[tiankong_count]); cvSetImageROI(dst, rect); int detect_l = max(0, rect.x - rect.width); int detect_t = max(0, rect.y - rect.height); int detect_r = min(dst->width - 1, rect.x + 2 * rect.width - 1); int detect_b = min(dst->height - 1, rect.y + 2 * rect.height - 1); CvRect rect_detect = cvRect(detect_l, detect_t, detect_r - detect_l + 1, detect_b - detect_t + 1); int red_area = GetTianKongTiRedCount(dst, rect, rect_detect); 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].question_index = qs.question_index; tiankongti_result_value[tiankong_count].question_code = qs.question_code; tiankongti_result_value[tiankong_count].maxscore = 0; tiankongti_result_value[tiankong_count].omr_question_type = TIANKONGTI; tiankong_count++; } return IDF_SUCCESS; } int CResultReader::GetZhuGuanTiRedCount(IplImage * dst, const CvRect& rect, const CvRect& normal_rect, int * red_counts, int * red_in_counts, int count) { if (dst->nChannels != 3){ return 0; } IplImage* red = NULL; BOOL s = GetRedBinary(dst, rect, &red); if (!s)return 0; #define GET_ZHUGUANTI_REDCOUNT_DEBUG 0 #if GET_ZHUGUANTI_REDCOUNT_DEBUG cvShowImage("sss", red); cvWaitKey(0); #endif 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 - 1 < top + 1){ cvDrawContours(red, (CvSeq *)c, cvScalar(0), cvScalar(0), 0, CV_FILLED, 8); /***求出轮廓重心*****/ /*cvDrawRect(temp,cvPoint(b_rect.x,b_rect.y),cvPoint(b_rect.x+b_rect.width-1,b_rect.y+b_rect.height-1),cvScalar(0),CV_FILLED); cvDrawContours(temp,(CvSeq *)c,cvScalar(255),cvScalar(255),0,CV_FILLED,8); int sum_x=0,sum_y=0,sum_count=0; for (int y=b_rect.y,end_y=b_rect.y+b_rect.height,end_x=b_rect.x+b_rect.width;ywidth; int h = red->height; for (int x = 0; x < w; x++) { int option_index = (count - 1) - x*count / w; for (int y = 0; y < h; y++) { if (CV_IMAGE_ELEM(red, unsigned char, y, x)){ red_counts[option_index]++; if (y <= bottom - 1 && y >= top + 1){ red_in_counts[option_index]++; } } } } cvReleaseImage(&red); return IDF_SUCCESS; } int CResultReader::GetTianKongTiRedCount(IplImage * dst, const CvRect& rect_normal, const CvRect& rect_detect) { CvRect rect = cvGetImageROI(dst); if (dst->nChannels != 3){ 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; y < red->height; y++) { unsigned char * red_row_first = (unsigned char *)(red->imageData + (y*red->widthStep)); for (int x = 0; x < red->width; x++) { if (red_row_first[x]){ redPoints.push_back(cvPoint2D32f(x, y)); } } } #define GET_TIANKONGTI_REDCOUNT_DEBUG 0 #if GET_TIANKONGTI_REDCOUNT_DEBUG cvShowImage("sss", red); cvWaitKey(0); #endif 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 (int i = 0; i < redPoints.size(); i++) { double distance = cvPointPolygonTest(c, redPoints[i], FALSE); if (distance >= 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; } BOOL CResultReader::GetRedBinary(IplImage * dst, const CvRect& rect_detect, IplImage ** red_binary) { #define rename_image(img,new_name) IplImage * new_name = img; img = NULL; if (dst == NULL || dst->nChannels != 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); 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 * 13 / 100; const int hsv_s_valve_2 = 255 * 23 / 100; const int hsv_valve_high = 255 * (23 + 70) / 100; const int hsv_valve_low = 255 * (13 + 60) / 100; for (int y = 0; y < h; y++) { unsigned char * hsv_row_first = (unsigned char *)(hsv->imageData + 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 < w; x++, hsv_offset += 3) { if (HSV_VALUE_V >= 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; } } 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, 1);//膨胀图像 cvDilate(red_high, red_high, element, 1);//膨胀图像 cvDilate(black, black_dilate, element, 1);//膨胀图像 for (int y = 0; y < h; y++) { unsigned char * binary_row_first = (unsigned char *)(binary->imageData + 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; x < w; x++) { red_row_first[x] = (red1_row_first[x] && !black_dilate_row_first[x] && ((!binary_row_first[x]) || red2_row_first[x])) ? 255 : 0; } } rename_image(red_high, red_dilate); cvDilate(red, red_dilate, element, 2);//膨胀图像 for (int y = 0; y < h; y++) { unsigned char * red1_row_first = (unsigned char *)(red_low->imageData + 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; x < w; x++) { red_row_first[x] = (red_row_first[x] || (red_dilate_row_first[x] && (red1_row_first[x] && !black_row_first[x]))) ? 255 : 0; } } cvDilate(red, red_dilate, element, 1);//膨胀图像 for (int y = 0; y < h; y++) { 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; x < w; x++) { if (!red_row_first[x] && black_row_first[x] && red_dilate_row_first[x]){ red_row_first[x] = 255; } } } cvReleaseStructuringElement(&element); *red_binary = red; //red1作为返回图像 不释放 cvReleaseImage(&hsv); //cvReleaseImage(&gray); cvReleaseImage(&binary); cvReleaseImage(&black); cvReleaseImage(&black_dilate); cvReleaseImage(&red_low); //cvReleaseImage(&red_high); return TRUE; } }