ResultReader.cpp 75 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096
  1. #include "StdAfx.h"
  2. #include "ResultReader.h"
  3. #include "Affine2DEstimator0.h"
  4. #include <stdlib.h>
  5. #include "CrossDetector.h"
  6. #include "IdentifyArea.h"
  7. std::string g_appFilePathName;
  8. namespace identify{
  9. CResultReader::CResultReader(void)
  10. {
  11. HMODULE module = GetModuleHandle(0);
  12. char pFileName[MAX_PATH + 2] = { 0 };
  13. GetModuleFileNameA(module, pFileName, MAX_PATH);
  14. std::string strPath = pFileName;
  15. int pos = strPath.find_last_of('\\', strPath.length());
  16. g_appFilePathName = strPath.substr(0, pos);
  17. strPath = strPath.substr(0, pos) + "\\..\\config.ini";
  18. int nType = GetPrivateProfileIntA("USER", "algorithm_boption", 1, strPath.c_str());
  19. m_nBxuanxiang = (nType == 1);
  20. knn = KNearest::create();
  21. }
  22. CResultReader::~CResultReader(void)
  23. {
  24. }
  25. inline unsigned char GetGrayFromBGR(const IplImage * img, int x, int y)
  26. {
  27. #define RGB_GRAY(B,G,R) ((R*38 + G*75 + B*15) >> 7)
  28. 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));
  29. }
  30. inline unsigned char GetGrayFromGray(const IplImage * img, int x, int y)
  31. {
  32. return CV_IMAGE_ELEM(img, unsigned char, y, x);
  33. }
  34. int CResultReader::ReadResult(const IplImage* img, int schemaIndex, cv::Mat transform, double scale, int dir, OMR_RESULT* out_result)
  35. {
  36. knn->clear();
  37. point_muban.clear();
  38. point_shijuan.clear();
  39. this->omr_result = (OMR_RESULT*)out_result;
  40. this->m_pageDirection = dir;
  41. m_AffineTransform = transform;
  42. m_Scaler0 = scale;
  43. SetDefaultOMR_Result(*omr_result);
  44. src = (IplImage*)img;
  45. if (src == NULL) return -1;
  46. if (src->nChannels == 1) _GetGray = &GetGrayFromGray;
  47. if (src->nChannels == 3) _GetGray = &GetGrayFromBGR;
  48. return ReadResult(schemaIndex);
  49. }
  50. //绘出识别位置
  51. void DrawIdentify(IplImage * dst_img, OMR_RESULT* omr_result)
  52. {
  53. cvResetImageROI(dst_img);
  54. if (omr_result->identified){
  55. for (int j = 0; j < omr_result->locatepoint_result.size(); j++){
  56. vector<LOCATE_POINT_RESULT>& option = omr_result->locatepoint_result;
  57. cvDrawRect(dst_img,
  58. cvPoint(cvRound(option[j].centerx - option[j].width / 2.0), cvRound(option[j].centery - option[j].height / 2.0)),
  59. cvPoint(cvRound(option[j].centerx + option[j].width / 2.0), cvRound(option[j].centery + option[j].height / 2.0)),
  60. cvScalar(0, 0, 255));
  61. }
  62. for (int i = 0; i < omr_result->group_result.size(); i++)
  63. {
  64. vector<KGUANTI_OPTION_RESULT> &option = omr_result->group_result[i].option;
  65. for (int j = 0; j < option.size(); j++)
  66. {
  67. cvDrawRect(dst_img,
  68. cvPoint(cvRound(option[j].centerx - option[j].width / 2.0), cvRound(option[j].centery - option[j].height / 2.0)),
  69. cvPoint(cvRound(option[j].centerx + option[j].width / 2.0), cvRound(option[j].centery + option[j].height / 2.0)),
  70. cvScalar(0, 0, 255));
  71. }
  72. }
  73. }
  74. }
  75. int CResultReader::ReadResult(int shemaIndex)
  76. {
  77. const ISCH_SCHEMA_PAGE& schemaPage = (*schemaPages)[shemaIndex];
  78. int ret;
  79. //查找辅助定位关系
  80. /************************定位点位置*********************************************/
  81. double fre = getTickFrequency();
  82. int64 t0 = cvGetTickCount();
  83. ret = findAssitLocate(schemaPage);
  84. int64 t1 = cvGetTickCount();
  85. double t = (t1 - t0) / fre;
  86. if (ret != IDF_SUCCESS) {
  87. return ret;
  88. }
  89. /************************定位点位置*********************************************/
  90. ret = ReadDingWeiDian(schemaPage);
  91. if (ret != IDF_SUCCESS) {
  92. return ret;
  93. }
  94. /************************根据给定区域识别二维码*********************************************/
  95. ret = ReadBarCode(schemaPage);
  96. if (ret != IDF_SUCCESS) {
  97. return ret;
  98. }
  99. /************************根据给定区域分析填涂项*********************************************/
  100. ret = ReadKeGuanTi(schemaPage);
  101. if (ret != IDF_SUCCESS) {
  102. return ret;
  103. }
  104. ret = ReadQuestionScore(schemaPage);
  105. if (ret != IDF_SUCCESS) {
  106. return ret;
  107. }
  108. /************************根据给定区域切割图片*********************************************/
  109. ret = ClipImg(schemaPage);
  110. if (ret != IDF_SUCCESS) {
  111. return ret;
  112. }
  113. omr_result->card_index = schemaPage.index;
  114. omr_result->identified = TRUE;
  115. //cvResetImageROI((IplImage*)src);
  116. //DrawIdentify((IplImage*)src,omr_result);
  117. //char file_name[512];
  118. //sprintf_s(file_name,"%sresult_%05d.png","D:\\img\\",(int)omr_result->phy_card_number);
  119. //cvSaveImage(file_name,src);
  120. {
  121. return IDF_SUCCESS;
  122. }
  123. }
  124. 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)
  125. {
  126. int gray;//临时变量,灰度值
  127. //int tembackcolor=max((anlyseResult.globalBackGround+200)/2,200);
  128. CvRect rr = GetJiaoZhengResultRect(item);
  129. int tembackcolor = max(anlyseResult.backGroundGray - 30, 200);
  130. int left = int(rr.x);
  131. int top = int(rr.y);
  132. int right = int(rr.x + rr.width);
  133. int bottom = int(rr.y + rr.height);
  134. int vtop = (int)(rr.y - rr.height*0.25 + 0.5);
  135. /*******************统计字符区域属性************************************/
  136. int cl = left + ((right - left + 1) + 2) / 4;
  137. int cr = left + ((right - left + 1) * 3 + 2) / 4;
  138. //int ct=top+((bottom-top+1)+2)/4;
  139. //int cb=top+((bottom-top+1)*3+2)/4;
  140. int ct = top;
  141. int cb = bottom;
  142. //初始化字符区域参数
  143. char_area_avg_gray = 0;
  144. char_area_black_count = 0;
  145. char_area_size = 0;
  146. for (int y = ct; y <= cb; y++)
  147. {
  148. for (int x = cl; x <= cr; x++)
  149. {
  150. gray = GetGray(dst, x, y);
  151. char_area_size++;
  152. if (gray < tembackcolor){
  153. char_area_avg_gray += gray;
  154. char_area_black_count++;
  155. }
  156. }
  157. }
  158. if (char_area_black_count > 0)char_area_avg_gray /= char_area_black_count;
  159. //灰度直方图
  160. int gray256[260];
  161. cellSize = 0;
  162. memset(gray256, 0, sizeof(gray256));
  163. double yRatio, xRatio, maxRatio;
  164. double dist;
  165. if (item.width >= item.height){
  166. xRatio = 1.0;
  167. yRatio = (item.width / (double)item.height)*(1 - 0.3);
  168. if (yRatio < 1)yRatio = 1;
  169. }
  170. else{
  171. yRatio = 1.0;
  172. xRatio = (item.height / (double)item.width)*(1 - 0.3);
  173. if (xRatio < 1)xRatio = 1;
  174. }
  175. double yd = item.centery;
  176. double xd = item.centerx;
  177. //理想点数
  178. int li_xiang_dian_shu = item.width*item.height;
  179. double dx;
  180. double dy;
  181. maxRatio = sqrt(xRatio*xRatio + yRatio*yRatio);
  182. xRatio = xRatio / (item.width / 2.0);
  183. yRatio = yRatio / (item.height / 2.0);
  184. xRatio = xRatio / maxRatio;
  185. yRatio = yRatio / maxRatio;
  186. refArea = 0;
  187. double distSum = 0;
  188. avg_gray = 0;
  189. grayNum = 0;
  190. for (int y = top; y <= bottom; y++)
  191. {
  192. for (int x = left; x <= right; x++)
  193. {
  194. gray = GetGray(dst, x, y);
  195. gray256[gray]++;
  196. cellSize++;
  197. if (gray < tembackcolor){
  198. avg_gray += gray;
  199. grayNum++;
  200. }
  201. dx = (x - xd)*xRatio;
  202. dy = (y - yd)*xRatio;
  203. dist = sqrt(dx*dx + dy*dy);
  204. gray = max(0, 255 - gray - 32);
  205. refArea += gray*(1 - dist);
  206. distSum += (1 - dist);
  207. }
  208. }
  209. avg_gray = grayNum > 0 ? avg_gray / grayNum : 256;
  210. refArea /= 16;
  211. refArea /= distSum;
  212. //灰度上限
  213. int grayUp = 256 - schemaPage.hei_du_ling_min_du * 16;
  214. mo_hu_du = 0;
  215. //合格黑点数
  216. int he_ge_hei_dian_shu = 0;
  217. for (int i = 0; i < grayUp; i++)
  218. {
  219. if (gray256[i] > 0){
  220. he_ge_hei_dian_shu += gray256[i];
  221. mo_hu_du += (i*gray256[i]);
  222. }
  223. }
  224. mo_hu_du = he_ge_hei_dian_shu > 0 ? mo_hu_du / he_ge_hei_dian_shu : 0;
  225. double ping_jun_hei_du = he_ge_hei_dian_shu > 0 ? mo_hu_du / he_ge_hei_dian_shu : 0;
  226. diheidushu = 0;
  227. for (int i = min(255, tembackcolor - 1); i >= tembackcolor - 45 && i >= 0; i--)
  228. {
  229. diheidushu += gray256[i];
  230. }
  231. int i, endpos, flag = 0;
  232. int hui_du_he = 0;
  233. int hei_dian_shu = 0;
  234. for (i = 0, endpos = grayUp; i < endpos; i++)
  235. {
  236. if (gray256[i] > 0){
  237. if (flag == 0){
  238. flag = 1;
  239. endpos = min(grayUp, i + 40);
  240. }
  241. hui_du_he += (i*gray256[i]);
  242. hei_dian_shu += gray256[i];
  243. }
  244. if (hei_dian_shu > li_xiang_dian_shu*0.1 || hei_dian_shu >= he_ge_hei_dian_shu*0.3 + 1){
  245. endpos = i;
  246. i++;
  247. break;
  248. }
  249. }
  250. for (; i < grayUp&&hei_dian_shu < dianshu_meihaomi*dianshu_meihaomi / 4 + 1 && hei_dian_shu < he_ge_hei_dian_shu*0.3 + 1; i++)
  251. {
  252. hui_du_he += (i*gray256[i]);
  253. hei_dian_shu += gray256[i];
  254. }
  255. endpos = i;
  256. gao_heidu = hei_dian_shu > 0 ? (255 - hui_du_he / hei_dian_shu) / 16 : 0;
  257. refArea /= max(1.0, gao_heidu - 2);
  258. /************确定清晰度**************************/
  259. int pnt_high = 0, pnt_low = 0, pnt_mid = 0;
  260. int pos1, pos2, pos3;
  261. double minRatio = 0.3; maxRatio = 0.8;
  262. pos1 = 255 - (int)(gao_heidu*maxRatio * 16);
  263. for (i = 0; i <= pos1; i++)
  264. {
  265. pnt_high += gray256[i];
  266. }
  267. for (i = pos1 + 1; i < grayUp&&pnt_high < dianshu_meihaomi*dianshu_meihaomi / 4 + 1; i++)
  268. {
  269. pnt_high += gray256[i];
  270. }
  271. pos1 = i;
  272. pos2 = hei_dian_shu*minRatio >= 3 ? 255 - (int)(gao_heidu*minRatio * 16) : 255 - 48;
  273. pos3 = min(pos2, pos1 + 16);
  274. for (i = pos1 + 1; i <= pos3; i++)
  275. {
  276. pnt_mid += gray256[i];
  277. }
  278. for (i = pos3 + 1; i <= pos2; i++)
  279. {
  280. pnt_low += gray256[i];
  281. }
  282. if (pnt_high == 0){ return IDF_DIVIDE_ZERO; }
  283. gao_heidu = max(0.0, gao_heidu);
  284. mo_hu_du = ((pnt_low + pnt_mid) / (double)pnt_high + pnt_low / (double)(pnt_high + pnt_mid)) / 2.0;
  285. mo_hu_du = min(mo_hu_du, gao_heidu - ping_jun_hei_du);
  286. mo_hu_du = min(min(gao_heidu, mo_hu_du), 5.0);
  287. mo_hu_du = max(0.0, mo_hu_du);
  288. return IDF_SUCCESS;
  289. }
  290. int CResultReader::ReadKeGuanTi(const ISCH_SCHEMA_PAGE &schemaPage)
  291. {
  292. if (m_nBxuanxiang){
  293. auto _items = schemaPage.items;
  294. if (m_nBxuanxiang == 1 && schemaPage.groups.size() > 0){
  295. try{
  296. auto pGetCVRect = [&](const ISCH_SCHEMA_ITEM* code)->CvRect{
  297. CvRect result_rect;
  298. if (code){
  299. result_rect = GetResultRect(*code);
  300. }
  301. return result_rect;
  302. };
  303. std::map<GROUP_TYPE, std::vector<int>> _map_groups_by_type;
  304. for (int groupIndex = 0; groupIndex < schemaPage.groups.size(); groupIndex++)
  305. {
  306. _map_groups_by_type[schemaPage.groups[groupIndex].group_type].push_back(groupIndex);
  307. }
  308. std::map<int, IdentifyGroup*> _map_group;
  309. std::vector<IdentifyArea*> _vct_release;
  310. for (auto it : _map_groups_by_type)
  311. {
  312. IdentifyArea *ptr_area = new IdentifyArea(it.second.size());
  313. ptr_area->type = static_cast<GROUP_TYPE_IDENTIFY>(it.first);
  314. _vct_release.push_back(ptr_area);
  315. int nIndex = 0;
  316. for (auto it_group : it.second)
  317. {
  318. const ISCH_IDENTIFY_GROUP& group = schemaPage.groups[it_group];
  319. IdentifyGroup*ptr_group = ptr_area->get_group_by_index(nIndex++);
  320. _map_group[it_group] = ptr_group;
  321. if (ptr_group){
  322. bool mul = true;
  323. switch (group.omr_out_type)
  324. {
  325. case OMR_OUT_TYPE_SINGLE_NONSTRICT_ERROR:
  326. case OMR_OUT_TYPE_SINGLE_NONSTRICT:
  327. case OMR_OUT_TYPE_SINGLE_STRICT:
  328. mul = false;
  329. break;
  330. case OMR_OUT_TYPE_MUTIL_STRICT:
  331. mul = true;
  332. break;
  333. }
  334. ptr_group->init(group.itemCount, std::to_string(group.nID).c_str(), mul);
  335. for (int itemindex = 0; itemindex < group.itemCount; itemindex++){
  336. IdentifyItem*ptr_item = ptr_group->get_item_by_index(itemindex);
  337. if (ptr_item){
  338. const ISCH_SCHEMA_ITEM*ptr_sc_item = &_items[group.itemIndex[itemindex]];
  339. auto rc = pGetCVRect(ptr_sc_item);
  340. ptr_item->x = rc.x;
  341. ptr_item->y = rc.y;
  342. ptr_item->w = rc.width;
  343. ptr_item->h = rc.height;
  344. strcpy(ptr_item->name, ptr_sc_item->OutChar);
  345. //ptr_item->name[0] = ptr_sc_item->OutChar[0];
  346. }
  347. }
  348. }
  349. }
  350. IplImage*dst_gray_img = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
  351. cvCvtColor(src, dst_gray_img, CV_BGR2GRAY);
  352. try{
  353. if (0 == api_ttpd_analysis_part(cv::cvarrToMat(dst_gray_img), ptr_area)){
  354. }
  355. }
  356. catch (cv::Exception e){
  357. const char *w = e.what();
  358. int i = 0; ++i;
  359. }
  360. cvReleaseImage(&dst_gray_img);
  361. }
  362. omr_result->group_result.resize(schemaPage.groups.size());
  363. identify::result::KEGUANTI_RESULT* ketuanti_result_value = omr_result->group_result.data();
  364. for (int groupIndex = 0; groupIndex < schemaPage.groups.size() && groupIndex < _map_group.size(); groupIndex++)
  365. {
  366. const ISCH_IDENTIFY_GROUP& group = schemaPage.groups[groupIndex];
  367. bool mul = true;
  368. switch (group.omr_out_type)
  369. {
  370. case OMR_OUT_TYPE_SINGLE_NONSTRICT_ERROR:
  371. case OMR_OUT_TYPE_SINGLE_NONSTRICT:
  372. case OMR_OUT_TYPE_SINGLE_STRICT:
  373. mul = false;
  374. if (_map_group[groupIndex]->select_count == _map_group[groupIndex]->item_count) // 单选题如果全选,结果值会保留全部值
  375. {
  376. mul = true;
  377. }
  378. break;
  379. case OMR_OUT_TYPE_MUTIL_STRICT:
  380. mul = true;
  381. break;
  382. }
  383. std::string omr_str = get_str_by_identify_group(mul ? 1 : 0, _map_group[groupIndex], schemaPage.option_spacer);
  384. ketuanti_result_value[groupIndex].answer = omr_str;
  385. ketuanti_result_value[groupIndex].question_state = OMR_QUESTION_STATE::OMR_QUESTION_STATE_NORMAL;
  386. }
  387. for (auto it : _vct_release){
  388. delete it;
  389. }
  390. _vct_release.clear();
  391. }
  392. catch (cv::Exception e){
  393. const char * ss = e.what();
  394. return IDF_FAILURE;
  395. }
  396. int global_background_color_avg = caculate_global_background(schemaPage);
  397. anlyseResult.backGroundGray = global_background_color_avg;
  398. return IDF_SUCCESS;
  399. }
  400. }
  401. else{
  402. int global_background_color_avg = caculate_global_background(schemaPage);
  403. anlyseResult.backGroundGray = global_background_color_avg;
  404. int ret;
  405. for (int i = 0; i < schemaPage.items.size(); i++)
  406. {
  407. ret = caculate_item_property(schemaPage, schemaPage.items[i], src, anlyseResult.itemAnalyseResult[i]);
  408. if (ret != IDF_SUCCESS)return ret;
  409. }
  410. caculate_item_global_property(schemaPage);
  411. ret = GenerateOmrStr(schemaPage);
  412. }
  413. return IDF_SUCCESS;
  414. }
  415. int CResultReader::GenerateOmrStr(const ISCH_SCHEMA_PAGE& schemaPage)
  416. {
  417. #define MAX_ITEM 64
  418. #define QQM_ADD 0 // 马百泉 2020.08 针对空白卷未填涂识别错误的修改代码
  419. char omr_str[512];
  420. int omr_str_len = 0;
  421. enum SelectType{
  422. //未选中
  423. UNSELECT,
  424. //不确定
  425. UNCERTAIN,
  426. //选中
  427. SELECTED
  428. };
  429. //标记是否被选中
  430. SelectType sel[MAX_ITEM];
  431. SAMPLE_KEGUANTITUDIAN samples[MAX_ITEM];
  432. omr_result->group_result.resize(schemaPage.groups.size());
  433. KEGUANTI_RESULT* ketuanti_result_value = omr_result->group_result.data();
  434. for (int groupIndex = 0; groupIndex < schemaPage.groups.size(); groupIndex++)
  435. {
  436. omr_str_len = 0;
  437. memset(sel, UNSELECT, sizeof(sel));
  438. const ISCH_IDENTIFY_GROUP& group = schemaPage.groups[groupIndex];
  439. int pn = min(MAX_ITEM, group.itemCount);
  440. AnalyseResult::itemResult* results[MAX_ITEM];
  441. const ISCH_SCHEMA_ITEM* items[MAX_ITEM];
  442. #if QQM_ADD
  443. bool b_multiple = false; // 是否是多项填涂
  444. if (group.omr_out_type == OMR_OUT_TYPE_MUTIL_STRICT) // @林 确认是否正确
  445. b_multiple = true;
  446. #endif
  447. ketuanti_result_value[groupIndex].option.resize(pn);
  448. for (int i = 0; i < pn; i++){
  449. results[i] = &anlyseResult.itemAnalyseResult[group.itemIndex[i]];
  450. items[i] = &schemaPage.items[group.itemIndex[i]];
  451. SaveRect(results[i]->item_position, ketuanti_result_value[groupIndex].option[i]);
  452. }
  453. int maxgraynum = -1;
  454. int second_maxgraynum = -1;
  455. int mingraynum = 0xffffff;
  456. float max_balck_ref_area = 0;
  457. float min_balck_ref_area = 0;
  458. for (int i = 0; i < pn; i++)
  459. {
  460. 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; }
  461. #if QQM_ADD
  462. else {
  463. if (results[i]->gray_num > second_maxgraynum) {
  464. second_maxgraynum = results[i]->gray_num;
  465. }
  466. }
  467. #endif
  468. if (results[i]->gray_num < mingraynum){ mingraynum = results[i]->gray_num; min_balck_ref_area = results[i]->gray_num / (float)results[i]->cell_size; }
  469. }
  470. #if QQM_ADD
  471. if (!b_multiple) {
  472. for (int i = 0; i < pn; i++) {
  473. results[i]->same_group_unselected_gray_num = mingraynum;
  474. }
  475. }
  476. #endif
  477. int selected_num = 0;
  478. int unselect_num = 0;
  479. int uncertain_num = 0;
  480. for (int i = 0; i < pn; i++)
  481. {
  482. //被涂面积小于10%
  483. if (results[i]->gray_num < results[i]->cell_size*0.2){
  484. sel[i] = UNSELECT;
  485. unselect_num++;
  486. continue;
  487. }
  488. #if QQM_ADD
  489. // 小面积的填涂项 小于 0.6直接pass 太****
  490. if (results[i]->cell_size < 700 && results[i]->gray_num < results[i]->cell_size*0.6) {
  491. sel[i] = UNSELECT;
  492. unselect_num++;
  493. continue;
  494. }
  495. // 填涂面积超过0.8的 直接按填涂处理 怕被下面的误伤 0.8的占比即使是没有填涂图像,也是涂抹之类的
  496. if (results[i]->gray_num > results[i]->cell_size*0.8) {
  497. sel[i] = SELECTED;
  498. selected_num++;
  499. continue;
  500. }
  501. // 单选填涂面积中填涂的背景区域要超过0.2 & 面积不能太大 目前来说出问题的都是小填涂规格
  502. // 但是 确实也有0.75-0.8之间的填涂,最小的可能超过0.6这时候出错
  503. 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)) {
  504. if (results[i]->gray_num < (results[i]->same_group_unselected_gray_num + results[i]->cell_size*0.1)) {
  505. sel[i] = UNSELECT;
  506. unselect_num++;
  507. continue;
  508. }
  509. else { // 前景 0.1 - 0.2的 借用(灰度数-模糊边缘数)的数据再次判断下
  510. float fmin = 1.0; float ri = 0.0;
  511. for (int x = 0; x < pn; x++) {
  512. float tmp = (results[x]->gray_num - results[x]->mo_hu_bianyu_shu)*1.0 / results[x]->cell_size;
  513. if (x == i) { ri = tmp; continue; }
  514. if (tmp < fmin) { fmin = tmp; }
  515. }
  516. if (ri > (fmin + 0.2)) {
  517. sel[i] = SELECTED;
  518. selected_num++;
  519. continue;
  520. }
  521. else {
  522. sel[i] = UNSELECT;
  523. unselect_num++;
  524. continue;
  525. }
  526. }
  527. }
  528. #endif
  529. if (results[i]->gray_num < max(results[i]->same_page_unselected_gray_num*1.3, results[i]->same_page_unselected_gray_num + 35.)){
  530. sel[i] = UNSELECT;
  531. unselect_num++;
  532. continue;
  533. }
  534. /*if(results[i]->diheidushu>80&&results[i]->diheidushu>results[i]->gray_num*0.45){
  535. sel[i] =UNSELECT;
  536. unselect_num++;
  537. continue;
  538. }*/
  539. //面积超过65%
  540. if (results[i]->gray_num > results[i]->cell_size*0.60){
  541. #if QQM_ADD
  542. // 还有 占比 0.6-0.7之间的 & 大于最小值+0.2 但是仍然是空白的 只能按照硬规则处理
  543. // 202009.04 英语小填涂项 正常填涂(稍浅色) 0.6-0.7 未填涂0.2-0.3 出错. 添加限制
  544. if (results[i]->gray_num < results[i]->cell_size*0.7 && results[i]->cell_size < 700
  545. && (maxgraynum - second_maxgraynum) < results[i]->cell_size*0.25) {
  546. sel[i] = UNSELECT;
  547. unselect_num++;
  548. continue;
  549. }
  550. #endif
  551. sel[i] = SELECTED;
  552. selected_num++;
  553. continue;
  554. }
  555. //填涂面积相差达%50,将面积不小于最大点填涂面积的总面积%20的涂点视为填涂
  556. 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){
  557. sel[i] = SELECTED;
  558. selected_num++;
  559. continue;
  560. }
  561. //填涂面积相差达%30,将面积不小于最大点填涂面积的总面积%18的涂点视为填涂
  562. 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){
  563. sel[i] = SELECTED;
  564. selected_num++;
  565. continue;
  566. }
  567. //填涂面积相差达%20,将面积不小于最大点填涂面积的总面积%18的涂点视为填涂
  568. 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){
  569. sel[i] = SELECTED;
  570. selected_num++;
  571. continue;
  572. }
  573. //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.)){
  574. // sel[i] = SELECTED;
  575. // selected_num++;
  576. // continue;
  577. //}
  578. if (maxgraynum - results[i]->gray_num > results[i]->cell_size*0.2){
  579. sel[i] = UNSELECT;
  580. unselect_num++;
  581. continue;
  582. }
  583. sel[i] = UNCERTAIN;
  584. uncertain_num++;
  585. }
  586. for (int i = 0; i < pn; i++)
  587. {
  588. if (sel[i] == SELECTED){
  589. if (results[i]->gray_num > results[i]->cell_size*0.7)continue;
  590. int not_mo_hu_bianyu_gray_num = results[i]->gray_num - results[i]->mo_hu_bianyu_shu;
  591. if (not_mo_hu_bianyu_gray_num < results[i]->cell_size*0.45){
  592. for (int j = 0; j < pn; j++){
  593. if (sel[j] == UNSELECT){
  594. if (results[i]->gray_num < (results[j]->gray_num - results[j]->mo_hu_bianyu_shu)*1.5&&not_mo_hu_bianyu_gray_num < (results[j]->gray_num - results[j]->mo_hu_bianyu_shu)*1.3){
  595. sel[i] = UNSELECT;
  596. selected_num--;
  597. unselect_num++;
  598. break;
  599. }
  600. if (results[i]->gray_num<max(results[j]->gray_num*1.2, (double)results[j]->gray_num + 35)){
  601. sel[i] = UNSELECT;
  602. selected_num--;
  603. unselect_num++;
  604. break;
  605. }
  606. }
  607. }
  608. }
  609. }
  610. }
  611. if (selected_num<1 && maxgraynum>mingraynum*1.7&&maxgraynum>mingraynum + 100){
  612. for (int i = 0; i < pn; i++)
  613. {
  614. //面积超过65%
  615. 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){
  616. sel[i] = SELECTED;
  617. selected_num++;
  618. continue;
  619. }
  620. }
  621. }
  622. // 处理一下填涂后 橡皮擦拭后 干扰的
  623. #if QQM_ADD
  624. if (selected_num > 1 && !b_multiple) {
  625. int max_gaoheidu_index_ture = 0; // 高黑度.真
  626. for (int i = 0; i < pn; i++) {
  627. if (sel[i] == SELECTED) {
  628. if (results[i]->gaoheidushu > results[max_gaoheidu_index_ture]->gaoheidushu)
  629. max_gaoheidu_index_ture = i;
  630. }
  631. }
  632. for (int i = 0; i < pn; i++) {
  633. if (sel[i] == SELECTED) {
  634. if (results[i]->gaoheidushu < results[max_gaoheidu_index_ture]->gaoheidushu*0.5) {
  635. sel[i] = UNSELECT;
  636. selected_num--;
  637. unselect_num++;
  638. }
  639. }
  640. }
  641. }
  642. #endif
  643. double max_avg_gray = -1;
  644. double min_avg_gray = 99999999999;
  645. if (selected_num > 1){
  646. switch (group.omr_out_type){
  647. case OMR_OUT_TYPE_SINGLE_NONSTRICT_ERROR:
  648. case OMR_OUT_TYPE_SINGLE_NONSTRICT:
  649. case OMR_OUT_TYPE_SINGLE_STRICT:
  650. //单选题
  651. int max_gaoheidu_index = 0;
  652. for (int i = 0; i<pn; i++){
  653. if (sel[i] == SELECTED){
  654. if (results[i]->gray_num - results[i]->diheidushu>results[max_gaoheidu_index]->gray_num - results[max_gaoheidu_index]->diheidushu){
  655. max_gaoheidu_index = i;
  656. }
  657. }
  658. }
  659. for (int i = 0; i < pn; i++){
  660. if (sel[i] == SELECTED){
  661. 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){
  662. sel[i] = UNSELECT;
  663. selected_num--;
  664. unselect_num++;
  665. }
  666. }
  667. }
  668. for (int i = 0; i < pn; i++){
  669. if (sel[i] == SELECTED && i != max_gaoheidu_index)
  670. {
  671. sel[i] = UNSELECT;
  672. selected_num--;
  673. unselect_num++;
  674. }
  675. }
  676. break;
  677. }
  678. }
  679. for (int i = 0; i < pn; i++){
  680. samples[i].BlackRefArea = results[i]->gray_num / (float)results[i]->cell_size;
  681. samples[i].HighBlackRefArea = results[i]->gaoheidushu / (float)results[i]->cell_size;
  682. samples[i].LowBlackRefArea = results[i]->diheidushu / (float)results[i]->cell_size;
  683. samples[i].Blur = (float)results[i]->mohudu;
  684. samples[i].RefAvgGray = results[i]->avg_gray;
  685. }
  686. float maxblackrefarea = 0;
  687. float minblackrefarea = 99999;
  688. float maxhighblackrefarea = 0;
  689. float minrefavggray = 9999;
  690. for (int i = 0; i < pn; i++){
  691. if (maxblackrefarea < samples[i].BlackRefArea)maxblackrefarea = samples[i].BlackRefArea;
  692. if (minblackrefarea > samples[i].BlackRefArea)minblackrefarea = samples[i].BlackRefArea;
  693. if (maxhighblackrefarea < samples[i].HighBlackRefArea)maxhighblackrefarea = samples[i].HighBlackRefArea;
  694. 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;
  695. if (minrefavggray > avgGray)minrefavggray = avgGray;
  696. }
  697. for (int i = 0; i < pn; i++){
  698. samples[i].MaxBlackRefArea = maxblackrefarea;
  699. samples[i].MinBlackRefArea = minblackrefarea;
  700. samples[i].MaxHighBlackRefArea = maxhighblackrefarea;
  701. samples[i].MinRefAvgGray = minrefavggray;
  702. }
  703. //
  704. //for(int i=0;i<pn;i++){
  705. // cv::Mat sampleMat(1,9,CV_32F,&samples[i]);
  706. // Mat responseMat;
  707. // float response=0;
  708. // switch(group.omr_out_type){
  709. // case OMR_OUT_TYPE_MUTIL_STRICT:
  710. // ClassBB::ann_mutil->predict(sampleMat,responseMat);
  711. // break;
  712. // default:
  713. // ClassBB::ann_signal->predict(sampleMat,responseMat);
  714. // break;
  715. // }
  716. // float * p = responseMat.ptr<float>();
  717. // for (int m=0;m<9;m++)
  718. // {
  719. // response+=p[m];
  720. // }
  721. // memcpy(ketuanti_result_value[groupIndex].option[i].features,&samples[i],sizeof(float)*9);
  722. // /*
  723. // int selected=(response>4?SELECTED:UNSELECT);
  724. // if(sel[i]!=selected){
  725. // if(sel[i]==SELECTED||selected==SELECTED){
  726. // if(samples[i].BlackRefArea>0.65)sel[i]=SELECTED;
  727. // else if(samples[i].BlackRefArea<0.35)sel[i]=UNSELECT;
  728. // else sel[i]=(SelectType)selected;
  729. // if(samples[i].RefAvgGray>samples[i].MinRefAvgGray+50)sel[i]=UNSELECT;
  730. // }
  731. // }*/
  732. //}
  733. selected_num = 0;
  734. for (int i = 0; i < pn; i++){
  735. if (sel[i] == SELECTED){
  736. selected_num++;
  737. }
  738. }
  739. if (selected_num > 1){
  740. float max_not_bianyuan = 0;
  741. for (int i = 0; i < pn; i++){
  742. if (sel[i] == SELECTED&&max_not_bianyuan < results[i]->gray_num - results[i]->mo_hu_bianyu_shu){
  743. max_not_bianyuan = results[i]->gray_num - results[i]->mo_hu_bianyu_shu;
  744. }
  745. }
  746. for (int i = 0; i<pn; i++){
  747. if (sel[i] == SELECTED&&max_not_bianyuan>(results[i]->gray_num - results[i]->mo_hu_bianyu_shu) * 2){
  748. sel[i] = UNSELECT;
  749. selected_num--;
  750. }
  751. //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){
  752. // sel[i] = UNSELECT;
  753. // selected_num--;
  754. //}
  755. }
  756. }
  757. int omr_out_type = group.omr_out_type;
  758. if (selected_num > 1 && (omr_out_type&OTF_SINGLE)){
  759. float min_agv = 999;
  760. for (int i = 0; i<pn; i++){
  761. if (sel[i] == SELECTED&&min_agv>samples[i].RefAvgGray){
  762. min_agv = samples[i].RefAvgGray;
  763. }
  764. }
  765. for (int i = 0; i < pn; i++){
  766. if (sel[i] == SELECTED&&min_agv < samples[i].RefAvgGray - 25){
  767. sel[i] = UNSELECT;
  768. selected_num--;
  769. }
  770. }
  771. }
  772. if (selected_num > 1 && (omr_out_type&OTF_MUTIL)){
  773. float min_agv = 999;
  774. for (int i = 0; i<pn; i++){
  775. if (sel[i] == SELECTED&&min_agv>samples[i].RefAvgGray){
  776. min_agv = samples[i].RefAvgGray;
  777. }
  778. }
  779. for (int i = 0; i < pn; i++){
  780. if (sel[i] == SELECTED&&min_agv < samples[i].RefAvgGray - 50){
  781. sel[i] = UNSELECT;
  782. selected_num--;
  783. }
  784. }
  785. }
  786. /*
  787. if(selected_num<1){
  788. float max_raynum=0;
  789. for(int i=0;i<pn;i++){
  790. if(max_raynum<results[i]->gray_num)max_raynum=results[i]->gray_num;
  791. }
  792. int ss_count=0;const int min_threshold =80;
  793. int threshold =max(min_threshold ,(int)(results[0]->cell_size*0.2));
  794. for(int i=0;i<pn;i++){
  795. if(max_raynum<results[i]->gray_num+threshold)ss_count++;
  796. }
  797. for(int i=0;ss_count==1&&i<pn;i++){
  798. if(max_raynum>results[i]->gray_num+threshold){sel[i]==SELECTED;selected_num++;}
  799. }
  800. }*/
  801. int out_count;
  802. OMR_QUESTION_STATE question_state = OMR_QUESTION_STATE_NORMAL;
  803. switch (group.omr_out_type){
  804. case OMR_OUT_TYPE_SINGLE_NONSTRICT_ERROR:
  805. out_count = 0;
  806. if (selected_num == 1){
  807. for (int i = 0; i < pn; i++)
  808. {
  809. if (sel[i] == SELECTED){
  810. if (out_count > 0)omr_str[omr_str_len++] = schemaPage.option_spacer;
  811. strcpy(&omr_str[omr_str_len], items[i]->OutChar);
  812. omr_str_len += strlen(items[i]->OutChar);
  813. out_count++;
  814. }
  815. }
  816. }
  817. else if (selected_num > 1){
  818. question_state = OMR_QUESTION_STATE_DUOTU;
  819. }
  820. else if (selected_num < 1){
  821. question_state = OMR_QUESTION_STATE_LOUTU;
  822. }
  823. if (out_count == 0){
  824. //omr_str[omr_str_len++]=schemaPage.unselect_char;
  825. }
  826. break;
  827. case OMR_OUT_TYPE_MUTIL_STRICT:
  828. case OMR_OUT_TYPE_SINGLE_STRICT:
  829. out_count = 0;
  830. for (int i = 0; i < pn; i++)
  831. {
  832. if (sel[i] == SELECTED){
  833. if (out_count > 0)omr_str[omr_str_len++] = schemaPage.option_spacer;
  834. strcpy(&omr_str[omr_str_len], items[i]->OutChar);
  835. omr_str_len += strlen(items[i]->OutChar);
  836. out_count++;
  837. }
  838. }
  839. if (out_count == 0){
  840. //omr_str[omr_str_len++]=schemaPage.unselect_char;
  841. question_state = OMR_QUESTION_STATE_LOUTU;
  842. }
  843. else if (out_count > 1 && group.omr_out_type == OMR_OUT_TYPE_SINGLE_STRICT){
  844. question_state = OMR_QUESTION_STATE_DUOTU;
  845. }
  846. break;
  847. case OMR_OUT_TYPE_SINGLE_NONSTRICT:
  848. if (selected_num > 1){
  849. int maxgrayindex = -1;
  850. int maxgraynum = -1;
  851. for (int i = 0; i<pn; i++)
  852. {
  853. if (sel[i] == SELECTED&&results[i]->gray_num>maxgraynum){
  854. maxgraynum = results[i]->gray_num;
  855. maxgrayindex = i;
  856. }
  857. }
  858. for (int i = 0; i < pn; i++)
  859. {
  860. if (sel[i] == SELECTED&&i != maxgrayindex){
  861. sel[i] = UNSELECT;
  862. }
  863. }
  864. }
  865. out_count = 0;
  866. for (int i = 0; i < pn; i++)
  867. {
  868. if (sel[i] == SELECTED){
  869. if (out_count > 0)omr_str[omr_str_len++] = schemaPage.option_spacer;
  870. strcpy(&omr_str[omr_str_len], items[i]->OutChar);
  871. omr_str_len += strlen(items[i]->OutChar);
  872. out_count++;
  873. }
  874. }
  875. if (out_count == 0){
  876. //omr_str[omr_str_len++]=schemaPage.unselect_char;
  877. question_state = OMR_QUESTION_STATE_LOUTU;
  878. }
  879. break;
  880. }
  881. omr_str[omr_str_len] = '\0';
  882. ketuanti_result_value[groupIndex].answer = omr_str;
  883. ketuanti_result_value[groupIndex].question_state = OMR_QUESTION_STATE::OMR_QUESTION_STATE_NORMAL;
  884. }
  885. return 0;
  886. }
  887. int CResultReader::analyseOmrPanoramic(ISCH_SCHEMA_PAGE& schemaPage)
  888. {
  889. /*int i;
  890. int lev;
  891. int count; // 所有涂点个数
  892. int numAblePnt; // 参与分析的点的个数
  893. double maxblk[16];
  894. int numBlk[16];
  895. double maxBlur[16];
  896. int numBlur[16];
  897. double stdBlur;
  898. memset( numBlk, 0, sizeof(int) * 16 );
  899. memset( maxblk, 0, sizeof(double)*16);
  900. memset( maxBlur, 0, sizeof(double)*16);
  901. memset( numBlur, 0, sizeof(int)*16);
  902. count = schemaPage.items.size();
  903. numAblePnt = 0;
  904. double& m_avaMaxBlk = anlyseResult.avgMax_heidu;
  905. double& m_benchmarkBlk = anlyseResult.benchmarkBlk;
  906. double& m_benchmarkArea = anlyseResult.benchmarkAreaBlk;
  907. m_avaMaxBlk=0;
  908. for(i=0; i<count; i++)
  909. {
  910. AnalyseResult::itemResult& itemr= anlyseResult.itemAnalyseResult[i];
  911. if( itemr.heidu < m_benchmarkBlk ||itemr.xiangdui_value < m_benchmarkArea )
  912. continue;
  913. if( itemr.heidu< 4.0 ) continue;
  914. m_avaMaxBlk +=itemr.heidu;
  915. numAblePnt++;
  916. lev = int( itemr.heidu );
  917. maxblk[lev] += itemr.heidu;
  918. numBlk[lev] ++;
  919. lev = int( itemr.mohudu );
  920. maxBlur[lev] += itemr.mohudu;
  921. numBlur[lev] ++;
  922. //pPnt++;
  923. }
  924. if( numAblePnt > 0 )
  925. m_avaMaxBlk /= numAblePnt;
  926. else
  927. m_avaMaxBlk = 12;
  928. int stdId = 2;
  929. int numStd = numBlk[0] + numBlk[1] + numBlk[2];
  930. int numCur = numStd;
  931. for(i=3; i<16; i++)
  932. {
  933. numCur += ( numBlk[i] - numBlk[i-3] );
  934. if( numCur > numStd )
  935. {
  936. numStd = numCur;
  937. stdId = i;
  938. }
  939. }
  940. double stdBlk = maxblk[stdId-2] + maxblk[stdId-1] + maxblk[stdId];
  941. if( numStd > 0 )
  942. stdBlk /= numStd;
  943. else
  944. stdBlk = 12;
  945. // 计算模糊度代表值
  946. stdId = 2;
  947. numStd = numBlur[0] + numBlur[1] + numBlur[2];
  948. numCur = numStd;
  949. for(i=3; i<16; i++)
  950. {
  951. numCur += ( numBlur[i] - numBlur[i-3] );
  952. if( numCur > numStd )
  953. {
  954. numStd = numCur;
  955. stdId = i;
  956. }
  957. }
  958. stdBlur = maxBlur[stdId-2] + maxBlur[stdId-1] + maxBlur[stdId];
  959. if( numStd > 0 )
  960. stdBlur /= numStd;
  961. else
  962. stdBlur = 0;
  963. if( stdBlur < 2.0 )
  964. stdBlk -= stdBlur;
  965. else
  966. stdBlk -= 2.0;
  967. if( stdBlk < m_avaMaxBlk )
  968. m_avaMaxBlk = stdBlk;
  969. //统计字符区域的黑色点数的平均值
  970. if(schemaPage.groups.size()>0){
  971. int max_item =1;
  972. for (int gi=0;gi<schemaPage.groups.size();gi++)
  973. {
  974. if(schemaPage.groups[gi].itemCount>max_item) max_item = schemaPage.groups[gi].itemCount;
  975. }
  976. int * char_area_black_counts = new int[schemaPage.groups.size()];
  977. int cur_item_count;//当前选项的数量
  978. for (int ii=0;ii<max_item;ii++)
  979. {
  980. cur_item_count=0;
  981. long total_char_area_size =0;
  982. for (int gi=0;gi<schemaPage.groups.size();gi++)
  983. {
  984. if(schemaPage.groups[gi].itemCount>ii){
  985. AnalyseResult::itemResult & ir= anlyseResult.itemAnalyseResult[schemaPage.groups[gi].itemIndex[ii]];
  986. char_area_black_counts[cur_item_count] = ir.char_area_black_count;
  987. total_char_area_size +=ir.char_area_size;
  988. cur_item_count++;
  989. }
  990. }
  991. double char_area_size_avg =total_char_area_size/(double)cur_item_count;
  992. int temp;
  993. for (int m=0;m<cur_item_count;m++)
  994. {
  995. for (int n=m+1;n<cur_item_count;n++)
  996. {
  997. if(char_area_black_counts[n]<char_area_black_counts[m]){
  998. temp =char_area_black_counts[n];
  999. char_area_black_counts[n] =char_area_black_counts[m];
  1000. char_area_black_counts[m]=temp;
  1001. }
  1002. }
  1003. }
  1004. }
  1005. }*/
  1006. return(0);
  1007. }
  1008. int CResultReader::caculate_global_background(const ISCH_SCHEMA_PAGE& schemaPage)
  1009. {
  1010. IplImage t;
  1011. cvInitImageHeader(&t, cvSize(src->width, src->height), src->depth, src->nChannels, src->origin, src->align);
  1012. cvSetData(&t, src->imageData, src->widthStep);
  1013. IplImage * dst = &t;
  1014. int global_background_color_count = 0;
  1015. int global_background_color_avg = 0;
  1016. for (int i = 0; i < schemaPage.items.size(); i++)
  1017. {
  1018. CvRect result_rect = GetJiaoZhengResultRect(schemaPage.items[i]);
  1019. int left = int(result_rect.x);
  1020. int top = int(result_rect.y);
  1021. int right = int(result_rect.x + result_rect.width);
  1022. int bottom = int(result_rect.y + result_rect.height);
  1023. int vtop = (int)(result_rect.y - (result_rect.height + 2) / 4);
  1024. int vbottom = (int)(result_rect.y + result_rect.height + (result_rect.height + 2) / 4);
  1025. int background_color_count = 0, background_color_avg = 0;
  1026. int gray;
  1027. left = max(0, left);
  1028. vtop = max(0, vtop);
  1029. right = min(dst->width - 1, right);
  1030. vbottom = min(dst->height - 1, vbottom);
  1031. for (int x = left; x <= right; x++)
  1032. {
  1033. gray = GetGray(dst, x, vtop);
  1034. if (gray > 160){ background_color_avg += gray; background_color_count++; }
  1035. gray = GetGray(dst, x, vbottom);
  1036. if (gray > 160){ background_color_avg += gray; background_color_count++; }
  1037. }
  1038. background_color_avg = background_color_count > 0 ? background_color_avg / background_color_count : 0;
  1039. if (background_color_avg > 100){
  1040. global_background_color_avg += background_color_avg;
  1041. global_background_color_count++;
  1042. }
  1043. }
  1044. global_background_color_avg = global_background_color_count > 0 ? global_background_color_avg / global_background_color_count : 0;
  1045. return global_background_color_avg;
  1046. }
  1047. unsigned char CResultReader::GetGray(const IplImage * dst, int x, int y)
  1048. {
  1049. return _GetGray(dst, x, y);
  1050. }
  1051. int CResultReader::ReadBarCode(const ISCH_SCHEMA_PAGE& schemaPage)
  1052. {
  1053. #define BARCODE_DEBUG_ENABLE 0
  1054. omr_result->qr_result.resize(schemaPage.codes.size());
  1055. CODE_RESULT* qr_result_value = omr_result->qr_result.data();
  1056. int success_count = 0;
  1057. int ret;
  1058. IplImage t;
  1059. cvInitImageHeader(&t, cvSize(src->width, src->height), src->depth, src->nChannels, src->origin, src->align);
  1060. cvSetData(&t, src->imageData, src->widthStep);
  1061. IplImage * img0 = &t;
  1062. cvResetImageROI(img0);
  1063. for (int i = 0; i < schemaPage.codes.size(); i++)
  1064. {
  1065. const ISCH_SCHEMA_CODE& code = schemaPage.codes[i];
  1066. CvRect rect = GetResultRect(code);
  1067. if ((rect.x + rect.width) > src->width)
  1068. {
  1069. rect.x = src->width - rect.width - 1;
  1070. }
  1071. if (rect.x<0)
  1072. {
  1073. rect.x = 0;
  1074. }
  1075. if (rect.y<0)
  1076. {
  1077. rect.y = 0;
  1078. }
  1079. if (rect.width + rect.x>src->width)
  1080. {
  1081. rect.width = src->width - rect.x;
  1082. }
  1083. if (rect.height + rect.y>src->height)
  1084. {
  1085. rect.height = src->height - rect.y;
  1086. }
  1087. SaveRect(rect, qr_result_value[i]);
  1088. IplImage* img = cvCreateImage(cvSize(rect.width, rect.height), src->depth, src->nChannels);
  1089. cvSetImageROI(img0, rect);
  1090. cvCopy(img0, img);
  1091. //cvSaveImage("D:\\img.jpg", img);
  1092. /*
  1093. IplImage* img= cvCreateImage(cvSize(cvRound(code.width),cvRound(code.height)),src->depth,src->nChannels) ;
  1094. Mat m =m_AffineTransform.clone();
  1095. CvMat map_matrix =m;
  1096. CvPoint2D32f p1 =warpAffinePoint<CvPoint2D32f,CvPoint2D32f>(cvPoint2D32f(0,0),&m_AffineTransform);
  1097. CvPoint2D32f p2 =warpAffinePoint<CvPoint2D32f,CvPoint2D32f>(cvPoint2D32f(code.centerx,code.centery),&m_AffineTransform);
  1098. CV_MAT_ELEM(map_matrix,double,0,2)+=(p2.x-p1.x);
  1099. CV_MAT_ELEM(map_matrix,double,1,2)+=(p2.y-p1.y);
  1100. cvGetQuadrangleSubPix(src,img,&map_matrix);
  1101. cvShowImage("img",img);
  1102. cvWaitKey(0);
  1103. */
  1104. std::string result;
  1105. //ret = PraseBarCode(img, result);
  1106. {
  1107. cv::Mat matDstGray = cvarrToMat(img);
  1108. char szRes[1024];
  1109. ret = api_parse_barcode_qrcode(matDstGray, CODE_BAR, szRes, 1024);
  1110. result = szRes;
  1111. }
  1112. // result = std::string(result, 1, result.size());
  1113. cvReleaseImage(&img);
  1114. if (ret == IDF_SUCCESS){
  1115. qr_result_value[i].qr_str = result;
  1116. omr_result->card_qrFlag = 1;
  1117. success_count++;
  1118. }
  1119. else{
  1120. omr_result->card_qrFlag = -1;
  1121. qr_result_value[i].qr_str = "";
  1122. }
  1123. }
  1124. return IDF_SUCCESS;
  1125. }
  1126. void CResultReader::SetDefaultOMR_Result(OMR_RESULT& omr_result)
  1127. {
  1128. omr_result.logic_page_number = -1;
  1129. omr_result.identified = FALSE;
  1130. omr_result.identify_msg = "没有匹配的模板";
  1131. omr_result.time = 0;
  1132. omr_result.card_index = -1;
  1133. omr_result.card_qrFlag = 0;
  1134. omr_result.card_name[0] = '\0';
  1135. }
  1136. int CResultReader::ClipImg(const ISCH_SCHEMA_PAGE& schemaPage)
  1137. {
  1138. IplImage t;
  1139. cvInitImageHeader(&t, cvSize(src->width, src->height), src->depth, src->nChannels, src->origin, src->align);
  1140. cvSetData(&t, src->imageData, src->widthStep);
  1141. IplImage * img0 = &t;
  1142. cvResetImageROI(img0);
  1143. omr_result->cut_area_result.resize(schemaPage.cutAreas.size());
  1144. CUT_AREA_RESULT* cut_area_result_value = omr_result->cut_area_result.data();
  1145. for (int i = 0; i < schemaPage.cutAreas.size(); i++)
  1146. {
  1147. const ISCH_SCHEMA_CLIP& cutArea = schemaPage.cutAreas[i];
  1148. CvRect rect = cvRect(cutArea.centerx - cutArea.width / 2, cutArea.centery - cutArea.height / 2, cutArea.width, cutArea.height);
  1149. SaveRect(rect, cut_area_result_value[i]);
  1150. const double scale = 3 / 3.0;
  1151. IplImage* img = cvCreateImage(cvSize(cvRound(cutArea.width*scale), cvRound(cutArea.height*scale)), src->depth, src->nChannels);
  1152. Mat m = m_AffineTransform.clone();
  1153. CvMat map_matrix = m;
  1154. CvPoint2D32f p1 = warpAffinePoint<CvPoint2D32f, CvPoint2D32f>(cvPoint2D32f(0, 0), &m);
  1155. CvPoint2D32f p2 = warpAffinePoint<CvPoint2D32f, CvPoint2D32f>(cvPoint2D32f(cutArea.centerx, cutArea.centery), &m);
  1156. CV_MAT_ELEM(map_matrix, double, 0, 0) /= scale;
  1157. CV_MAT_ELEM(map_matrix, double, 0, 1) /= scale;
  1158. CV_MAT_ELEM(map_matrix, double, 1, 0) /= scale;
  1159. CV_MAT_ELEM(map_matrix, double, 1, 1) /= scale;
  1160. CV_MAT_ELEM(map_matrix, double, 0, 2) += (p2.x - p1.x);
  1161. CV_MAT_ELEM(map_matrix, double, 1, 2) += (p2.y - p1.y);
  1162. cvGetQuadrangleSubPix(img0, img, &map_matrix);
  1163. if (img->nChannels == 3){
  1164. IplImage * temp = cvCreateImage(cvSize(img->width, img->height), IPL_DEPTH_8U, 1);
  1165. cvCvtColor(img, temp, CV_BGR2GRAY);
  1166. cvReleaseImage(&img);
  1167. img = temp;
  1168. }
  1169. vector<uchar> dst;
  1170. //cv::Mat _img(img);
  1171. cv::Mat _img = cv::cvarrToMat(img);
  1172. /*直方图拉伸增强图像*/
  1173. cv::Mat hist;
  1174. vector<float> range; range.push_back(0); range.push_back(255);
  1175. calcHist(vector<Mat>(1, _img), vector<int>(1, 0), Mat(), hist, vector<int>(1, 256), range);
  1176. int type = hist.type();
  1177. double sum_low = 0;
  1178. double sum_low2 = 0;
  1179. double sum_high = 0;
  1180. double sum_high2 = 0;
  1181. double imin = 0, imax = 255;
  1182. for (int idx_i = 0; idx_i < 128; idx_i++)
  1183. {
  1184. sum_low += hist.at<float>(idx_i, 0);
  1185. }
  1186. sum_low *= 0.5;
  1187. for (int idx_i = 0; idx_i < 128; idx_i++)
  1188. {
  1189. sum_low2 += hist.at<float>(idx_i, 0);
  1190. if (sum_low < sum_low2){ imin = idx_i; break; }
  1191. }
  1192. for (int idx_i = 255; idx_i > 220; idx_i--)
  1193. {
  1194. sum_high += hist.at<float>(idx_i, 0);
  1195. }
  1196. sum_high *= 0.8;
  1197. for (int idx_i = 255; idx_i > 220; idx_i--)
  1198. {
  1199. sum_high2 += hist.at<float>(idx_i, 0);
  1200. if (sum_high < sum_high2){ imax = idx_i; break; }
  1201. }
  1202. Mat lookup(1, 256, CV_8U);
  1203. for (int idx_i = 0; idx_i < imin; idx_i++)
  1204. {
  1205. lookup.at<unsigned char>(idx_i) = 0;
  1206. }
  1207. for (int idx_i = imin; idx_i <= imax; idx_i++)
  1208. {
  1209. lookup.at<unsigned char>(idx_i) = static_cast<uchar>(255 * (idx_i - imin) / (imax - imin) + 0.5);
  1210. }
  1211. for (int idx_i = imax + 1; idx_i < 256; idx_i++)
  1212. {
  1213. lookup.at<unsigned char>(idx_i) = 255;
  1214. }
  1215. cv::LUT(_img, lookup, _img);
  1216. /*保存图像*/
  1217. imencode(".png", _img, dst);
  1218. cut_area_result_value[i].obj_id = cutArea.nID;
  1219. cut_area_result_value[i].centerx = cutArea.centerx;
  1220. cut_area_result_value[i].centery = cutArea.centery;
  1221. cut_area_result_value[i].width = img->width;
  1222. cut_area_result_value[i].height = img->height;
  1223. cut_area_result_value[i].area_name = cutArea.area_name_by_questionNo;
  1224. cut_area_result_value[i].area_index = cutArea.markUnit;
  1225. cut_area_result_value[i].area_sub_index = cutArea.markUnitPart;
  1226. cut_area_result_value[i].img_data = dst;
  1227. cvReleaseImage(&img);
  1228. }
  1229. return IDF_SUCCESS;
  1230. }
  1231. void CResultReader::SetSchemaPages(boost::shared_ptr<const ISCH_Schema>schema)
  1232. {
  1233. this->schemaPages = schema;
  1234. }
  1235. template<typename T1, typename T2>
  1236. T2 CResultReader::warpAffinePoint(T1& src, Mat * map_matrix)
  1237. {
  1238. T2 r;
  1239. r.x = map_matrix->at<double>(0, 0)*src.x + map_matrix->at<double>(0, 1)*src.y + map_matrix->at<double>(0, 2);
  1240. r.y = map_matrix->at<double>(1, 0)*src.x + map_matrix->at<double>(1, 1)*src.y + map_matrix->at<double>(1, 2);
  1241. return r;
  1242. }
  1243. template<typename T1>
  1244. CvRect CResultReader::GetResultRect(T1& item)
  1245. {
  1246. CvRect r;
  1247. CvPoint2D32f p = warpAffinePoint<CvPoint2D32f, CvPoint2D32f>(cvPoint2D32f(item.centerx, item.centery), &m_AffineTransform);
  1248. if (m_pageDirection &(ROTATION_0 | ROTATION_180)){
  1249. r.width = cvRound(item.width*m_Scaler0);
  1250. r.height = cvRound(item.height*m_Scaler0);
  1251. }
  1252. else{
  1253. r.height = cvRound(item.width*m_Scaler0);
  1254. r.width = cvRound(item.height*m_Scaler0);
  1255. }
  1256. r.x = cvRound(p.x - r.width / 2.0);
  1257. r.y = cvRound(p.y - r.height / 2.0);
  1258. return r;
  1259. }
  1260. template<typename T1>
  1261. CvRect CResultReader::GetJiaoZhengResultRect(T1& item)
  1262. {
  1263. CvRect r;
  1264. CvPoint2D32f p = GetJiaoZhengResultPoint<CvPoint2D32f, CvPoint2D32f>(cvPoint2D32f(item.centerx, item.centery));
  1265. if (m_pageDirection &(ROTATION_0 | ROTATION_180)){
  1266. r.width = cvRound(item.width*m_Scaler0);
  1267. r.height = cvRound(item.height*m_Scaler0);
  1268. }
  1269. else{
  1270. r.height = cvRound(item.width*m_Scaler0);
  1271. r.width = cvRound(item.height*m_Scaler0);
  1272. }
  1273. r.x = cvRound(p.x - r.width / 2.0);
  1274. r.y = cvRound(p.y - r.height / 2.0);
  1275. return r;
  1276. }
  1277. template<class T>
  1278. void CResultReader::SaveRect(CvRect& rect, T& result)
  1279. {
  1280. result.centerx = rect.x + rect.width / 2.0;
  1281. result.centery = rect.y + rect.height / 2.0;
  1282. result.width = rect.width;
  1283. result.height = rect.height;
  1284. result.angle = 0;
  1285. }
  1286. int CResultReader::ReadDingWeiDian(const ISCH_SCHEMA_PAGE& schemaPage)
  1287. {
  1288. #define BARCODE_DEBUG_ENABLE 0
  1289. omr_result->locatepoint_result.resize(schemaPage.locatePoints.size());
  1290. LOCATE_POINT_RESULT* locatepoint_result_value = omr_result->locatepoint_result.data();
  1291. for (int i = 0; i < schemaPage.locatePoints.size(); i++)
  1292. {
  1293. const ISCH_SCHEMA_LOCATE_POINT& code = schemaPage.locatePoints[i];
  1294. CvRect rect = GetResultRect(code);
  1295. SaveRect(rect, locatepoint_result_value[i]);
  1296. }
  1297. return IDF_SUCCESS;
  1298. }
  1299. int CResultReader::caculate_item_property(const ISCH_SCHEMA_PAGE& schemaPage, const ISCH_SCHEMA_ITEM &item, const IplImage * dst0, AnalyseResult::itemResult& item_result)
  1300. {
  1301. IplImage t;
  1302. cvInitImageHeader(&t, cvSize(dst0->width, dst0->height), dst0->depth, dst0->nChannels, dst0->origin, dst0->align);
  1303. cvSetData(&t, dst0->imageData, dst0->widthStep);
  1304. IplImage * dst = &t;
  1305. int gray;
  1306. CvRect item_roi = GetJiaoZhengResultRect(item);
  1307. 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;
  1308. int tembackcolor = max(anlyseResult.backGroundGray - 30, 200);
  1309. GetCorrectedRect(item_roi, src, tembackcolor);
  1310. item_result.item_position = item_roi;
  1311. //模糊边缘点数
  1312. int mo_hu_bianyu_shu = 0;
  1313. for (int y = item_roi.y, endy = item_roi.y + item_roi.height; y < endy; y++)
  1314. {
  1315. for (int x = item_roi.x, endx = item_roi.x + item_roi.width; x < endx; x++)
  1316. {
  1317. int gray = GetGray(dst, x, y);
  1318. if (gray <= 128)continue;
  1319. if (gray >= tembackcolor)continue;
  1320. int sxx = min(dst->width - 1, max(0, x - 2));
  1321. int exx = min(dst->width - 1, max(0, x + 2));
  1322. int syy = min(dst->height - 1, max(0, y - 2));
  1323. int eyy = min(dst->height - 1, max(0, y + 2));
  1324. int gray_thresold = gray - 70;
  1325. //标记当前点是否是模糊的边缘点
  1326. bool ismohubianyuandian = false;
  1327. for (int yy = syy; !ismohubianyuandian&&yy <= eyy; yy++)
  1328. {
  1329. for (int xx = sxx; !ismohubianyuandian&&xx <= exx; xx++)
  1330. {
  1331. if (GetGray(dst, xx, yy) < gray_thresold){
  1332. ismohubianyuandian = true;
  1333. break;
  1334. }
  1335. }
  1336. }
  1337. if (ismohubianyuandian)mo_hu_bianyu_shu++;
  1338. }
  1339. }
  1340. int left = int(item_roi.x);
  1341. int top = int(item_roi.y);
  1342. int right = int(item_roi.x + item_roi.width);
  1343. int bottom = int(item_roi.y + item_roi.height);
  1344. //灰度直方图
  1345. int gray256[260];
  1346. memset(gray256, 0, sizeof(gray256));
  1347. for (int y = top; y <= bottom; y++)
  1348. {
  1349. for (int x = left; x <= right; x++)
  1350. {
  1351. gray = GetGray(dst, x, y);
  1352. gray256[gray]++;
  1353. }
  1354. }
  1355. int cellSize = (right - left + 1)*(bottom - top + 1);
  1356. int idx_first = 0;
  1357. for (int idx_gray = 0; idx_gray < 256; idx_gray++)
  1358. {
  1359. if (gray256[idx_gray] > 0){ idx_first = idx_gray; break; }
  1360. }
  1361. int sum_gray = 0;
  1362. int gray_num = 0;
  1363. for (int idx_gray = idx_first; idx_gray < tembackcolor&&idx_gray<256; idx_gray++)
  1364. {
  1365. gray_num += gray256[idx_gray];
  1366. sum_gray += (idx_gray*gray256[idx_gray]);
  1367. }
  1368. float avg_gray = gray_num > 0 ? sum_gray / (float)gray_num : 255;
  1369. int diheidushu = 0;
  1370. for (int idx_gray = tembackcolor - 1; idx_gray > tembackcolor - 40 && idx_gray > 128; idx_gray--)
  1371. {
  1372. diheidushu += gray256[idx_gray];
  1373. }
  1374. int gaoheidushu = 0;
  1375. for (int idx_gray = idx_first, end = idx_first + 40; idx_gray < tembackcolor&&idx_gray < end; idx_gray++)
  1376. {
  1377. gaoheidushu += gray256[idx_gray];
  1378. }
  1379. int midheidushu = max(0, gray_num - gaoheidushu - diheidushu);
  1380. double mo_hu_du = ((diheidushu + midheidushu) / (double)gaoheidushu + diheidushu / (double)(gaoheidushu + midheidushu)) / 2.0;
  1381. mo_hu_du = std::min(std::max(0.0, mo_hu_du), 5.0);
  1382. item_result.mo_hu_bianyu_shu = mo_hu_bianyu_shu;
  1383. item_result.gray_num = gray_num;
  1384. item_result.diheidushu = diheidushu;
  1385. item_result.gaoheidushu = gaoheidushu;
  1386. item_result.mohudu = mo_hu_du;
  1387. item_result.avg_gray = avg_gray;
  1388. item_result.cell_size = cellSize;
  1389. item_result.xiangdui_mianji = gray_num / (double)cellSize;
  1390. return IDF_SUCCESS;
  1391. }
  1392. bool sort_item_by_xiangdui_mianji(AnalyseResult::itemResult*item1, AnalyseResult::itemResult*item2){
  1393. return item1->xiangdui_mianji < item2->xiangdui_mianji;
  1394. }
  1395. void CResultReader::caculate_item_global_property(const ISCH_SCHEMA_PAGE & schemaPage)
  1396. {
  1397. vector<AnalyseResult::itemResult*> items;
  1398. int item_count = schemaPage.items.size();
  1399. for (int idx_item = 0; idx_item < item_count; idx_item++){
  1400. items.push_back(&anlyseResult.itemAnalyseResult[idx_item]);
  1401. }
  1402. std::sort(items.begin(), items.end(), sort_item_by_xiangdui_mianji);
  1403. if (items.size() >= 2 && items[0]->xiangdui_mianji < 0.6&&items[0]->xiangdui_mianji*1.5 < items[items.size() - 1]->xiangdui_mianji){
  1404. double sum_xiangdu_mianji = 0;
  1405. int xiangdui_mianji_count = 0;
  1406. double max_xiangduimianji = (items[items.size() - 1]->xiangdui_mianji - items[0]->xiangdui_mianji) / 3 + items[0]->xiangdui_mianji;
  1407. for (int idx_item = 0; idx_item < item_count&&items[idx_item]->xiangdui_mianji < max_xiangduimianji; idx_item++){
  1408. sum_xiangdu_mianji += items[idx_item]->xiangdui_mianji;
  1409. xiangdui_mianji_count++;
  1410. }
  1411. for (int idx_item = 0; idx_item < item_count; idx_item++){
  1412. items[idx_item]->same_page_unselected_gray_num = items[idx_item]->cell_size*(sum_xiangdu_mianji / xiangdui_mianji_count);
  1413. }
  1414. }
  1415. else {
  1416. for (int idx_item = 0; idx_item < item_count; idx_item++){
  1417. items[idx_item]->same_page_unselected_gray_num = items[idx_item]->cell_size*0.35;
  1418. }
  1419. }
  1420. }
  1421. bool sort_key_point_by_response(const KeyPoint& k1, const KeyPoint& k2){
  1422. return k1.response > k2.response;
  1423. }
  1424. int CResultReader::findAssitLocate(const ISCH_SCHEMA_PAGE& schemaPage)
  1425. {
  1426. IplImage t;
  1427. cvInitImageHeader(&t, cvSize(src->width, src->height), src->depth, src->nChannels, src->origin, src->align);
  1428. cvSetData(&t, src->imageData, src->widthStep);
  1429. IplImage * img = &t;
  1430. for (int i = 0; i < schemaPage.assistLocateArea.size(); i++)
  1431. {
  1432. cvResetImageROI(img);
  1433. int left, top, right, bottom;
  1434. const ISCH_SCHEMA_LOCATE_AREA& locateArea = schemaPage.assistLocateArea[i].locate_area;
  1435. const vector<KeyPoint>& locateAreaKeys = schemaPage.assistLocateArea[i].locateAreasKeyPoints;
  1436. const CvPoint locateAreaOffset = schemaPage.assistLocateArea[i].locateAreasOffset;
  1437. const Mat& locateAreaDescriptor = schemaPage.assistLocateArea[i].locateAreasDescriptor;
  1438. if (locateAreaDescriptor.rows < 1)continue;
  1439. const int ww0 = 100; const int hh0 = 100;
  1440. double tw = locateArea.width + ww0, th = locateArea.height + hh0;
  1441. CvRect rect = GetResultRect(locateArea);
  1442. left = std::max(0.0, std::min((double)img->width - 1, rect.x + (rect.width - tw) / 2));
  1443. right = std::max(0.0, std::min((double)img->width - 1, rect.x + (rect.width + tw) / 2));
  1444. top = std::max(0.0, std::min((double)img->height - 1, rect.y + (rect.height - th) / 2));
  1445. bottom = std::max(0.0, std::min((double)img->height - 1, rect.y + (rect.height + th) / 2));
  1446. cvSetImageROI(img, cvRect(left, top, right - left + 1, bottom - top + 1));
  1447. IplImage * grayImg = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
  1448. int64 t0 = cvGetTickCount();
  1449. cvCvtColor(img, grayImg, CV_BGR2GRAY);
  1450. int64 t01 = cvGetTickCount();
  1451. cvSmooth(grayImg, grayImg, CV_GAUSSIAN, 5);
  1452. Mat m_m = cv::cvarrToMat(grayImg, false);
  1453. std::vector<KeyPoint> keyPoints;
  1454. Mat descriptor;
  1455. int64 t1 = cvGetTickCount();
  1456. Ptr<FeatureDetector>pDetector = SurfFeatureDetector::create();// 这里我们用了SURF特征点
  1457. cv::Mat mask = cv::Mat::zeros(m_m.rows, m_m.cols, CV_8U);
  1458. const int ww = 100; const int ww_2 = (ww0 - ww) / 2;
  1459. const int hh = 100; const int hh_2 = (hh0 - hh) / 2;
  1460. mask(cvRect(ww_2, hh_2, ww, hh)).setTo(cv::Scalar(1));
  1461. mask(cvRect(mask.cols - ww - ww_2, hh_2, ww, hh)).setTo(cv::Scalar(1));
  1462. mask(cvRect(ww_2, mask.rows - hh0 - hh_2, ww, hh)).setTo(cv::Scalar(1));
  1463. mask(cvRect(mask.cols - ww - ww_2, mask.rows - hh0 - hh_2, ww, hh)).setTo(cv::Scalar(1));
  1464. mask(cvRect((mask.cols - ww) / 2, (mask.rows - hh) / 2, ww, hh)).setTo(cv::Scalar(1));
  1465. pDetector->detect(m_m, keyPoints, mask);
  1466. /*std::sort(keyPoints.begin(),keyPoints.end(),sort_key_point_by_response);
  1467. int size =std::max(min((int)keyPoints.size(),50),std::min(200,(int)keyPoints.size()*2/3));
  1468. keyPoints.resize(size);*/
  1469. int64 t2 = cvGetTickCount();
  1470. Ptr<DescriptorExtractor>pExtractor = SurfDescriptorExtractor::create(); // 提取SURF描述向量
  1471. pExtractor->compute(m_m, keyPoints, descriptor);
  1472. int64 t3 = cvGetTickCount();
  1473. vector<DMatch> Matches;
  1474. Ptr<DescriptorMatcher>pMatcher = new FlannBasedMatcher(); // 使用Flann匹配算法
  1475. int64 t3_1 = cvGetTickCount();
  1476. if (descriptor.rows > 0 && locateAreaDescriptor.rows > 0)pMatcher->match(descriptor, locateAreaDescriptor, Matches);
  1477. int64 t4 = cvGetTickCount();
  1478. if (Matches.size() >= 3){
  1479. vector<Point2f> _from;
  1480. vector<Point2f> _to;
  1481. for (int n = 0; n < Matches.size(); n++)
  1482. {
  1483. Point2f to0 = warpAffinePoint<const Point2f, Point2f >(Point2f(locateAreaKeys[Matches[n].trainIdx].pt.x + locateAreaOffset.x, locateAreaKeys[Matches[n].trainIdx].pt.x + locateAreaOffset.y), &m_AffineTransform);
  1484. Point2f to1 = Point2f(keyPoints[Matches[n].queryIdx].pt.x + left, keyPoints[Matches[n].queryIdx].pt.x + top);
  1485. if (((to0.x - to1.x)*(to0.x - to1.x) + (to0.y - to1.y)*(to0.y - to1.y))>35 * 35)continue;
  1486. _to.push_back(keyPoints[Matches[n].queryIdx].pt);
  1487. _from.push_back(locateAreaKeys[Matches[n].trainIdx].pt);
  1488. }
  1489. if (_from.size() >= 3){
  1490. // Show result
  1491. Mat _out; Mat _inliers;
  1492. int64 t5 = cvGetTickCount();
  1493. int su = estimateAffine2D0(_from, _to, _out, _inliers, 2);
  1494. int64 t6 = cvGetTickCount();
  1495. double tickFre = getTickFrequency();
  1496. 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 };
  1497. if (su > cv::max(5.0, _from.size()*0.1))
  1498. {
  1499. Point2f src[] = { Point2f(0, 0), Point2f(1000, 0), Point2f(0, 1000), Point2f(1000, 1000) };
  1500. Point2f dst[] = { warpAffinePoint<Point2f, Point2f>(src[0], &_out), warpAffinePoint<Point2f, Point2f>(src[1], &_out), warpAffinePoint<Point2f, Point2f>(src[2], &_out), warpAffinePoint<Point2f, Point2f>(src[3], &_out) };
  1501. double d_src[] = { GetDistance(src[0], src[1]), GetDistance(src[0], src[2]), GetDistance(src[1], src[2]), GetDistance(src[0], src[3]) };
  1502. double d_dst[] = { GetDistance(dst[0], dst[1]), GetDistance(dst[0], dst[2]), GetDistance(dst[1], dst[2]), GetDistance(dst[0], dst[3]) };
  1503. 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] };
  1504. double scale = 0;
  1505. for (int idx_s_i = 0, length_s = sizeof(scales) / sizeof(scales[0]); idx_s_i < length_s; idx_s_i++)
  1506. {
  1507. for (int idx_s_j = idx_s_i + 1; idx_s_j < length_s; idx_s_j++)
  1508. {
  1509. scale = max(scale, abs(scales[idx_s_i] - scales[idx_s_j]));
  1510. }
  1511. }
  1512. double d_duijiaoxian = abs(d_dst[2] / d_src[3] * d_dst[3] - d_dst[2]);
  1513. if (scale < 0.09&&d_duijiaoxian < 100){//变形过大
  1514. double centerx0 = locateArea.centerx;
  1515. double centery0 = locateArea.centery;
  1516. double centerx1 = locateArea.centerx - locateAreaOffset.x;
  1517. double centery1 = locateArea.centery - locateAreaOffset.y;
  1518. 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) };
  1519. 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) };
  1520. double dist[5];
  1521. bool is_all_less_thresold = true;
  1522. const double thresold = 20;
  1523. for (int idx_dist = 0; idx_dist < 5; idx_dist++)
  1524. {
  1525. Point2f point_dst0 = warpAffinePoint<Point2f, Point2f>(point_src0[idx_dist], &m_AffineTransform);
  1526. Point2f point_dst1 = warpAffinePoint<Point2f, Point2f>(point_src1[idx_dist], &_out);
  1527. double dx = point_dst1.x + left - point_dst0.x;
  1528. double dy = point_dst1.y + top - point_dst0.y;
  1529. dist[idx_dist] = sqrt(dx*dx + dy*dy);
  1530. if (dist[idx_dist] >= thresold){ is_all_less_thresold = false; break; }
  1531. }
  1532. if (is_all_less_thresold){
  1533. for (float x = locateArea.centerx - locateArea.width / 2.0 - locateAreaOffset.x, endx = locateArea.centerx + locateArea.width / 2.0 - locateAreaOffset.x; x < endx; x += 10)
  1534. {
  1535. for (float y = locateArea.centery - locateArea.height / 2.0 - locateAreaOffset.y, endy = locateArea.centery + locateArea.height / 2.0 - locateAreaOffset.y; y < endy; y += 10)
  1536. {
  1537. Point2f dst = warpAffinePoint<Point2f, Point2f>(Point2f(x, y), &_out);
  1538. point_muban.push_back(Point2f(locateAreaOffset.x + x, locateAreaOffset.y + y));
  1539. point_shijuan.push_back(Point2f(left + dst.x, top + dst.y));
  1540. }
  1541. }
  1542. }
  1543. }
  1544. }
  1545. }
  1546. }
  1547. cvReleaseImage(&grayImg);
  1548. }
  1549. if (point_muban.size() > 0){
  1550. cv::Mat response(point_muban.size(), 1, CV_32F);
  1551. cv::Mat trainData(point_muban.size(), 2, CV_32F);
  1552. for (int i = 0; i < point_muban.size(); i++)
  1553. {
  1554. trainData.at<float>(i, 0) = point_muban[i].x;
  1555. trainData.at<float>(i, 1) = point_muban[i].y;
  1556. response.at<float>(i, 0) = i;
  1557. }
  1558. Ptr<TrainData> traind = cv::ml::TrainData::create(trainData, ROW_SAMPLE, response);
  1559. knn->train(traind);
  1560. }
  1561. return IDF_SUCCESS;
  1562. }
  1563. void CResultReader::GetCorrectedRect(CvRect &rr, const IplImage * src, int tembackcolor)
  1564. {
  1565. IplImage t;
  1566. cvInitImageHeader(&t, cvSize(src->width, src->height), src->depth, src->nChannels, src->origin, src->align);
  1567. cvSetData(&t, src->imageData, src->widthStep);
  1568. IplImage * dst = &t;
  1569. const int detect_size = 3;
  1570. int w = rr.width;
  1571. int h = rr.height;
  1572. int detect_src_left = max(0, rr.x - detect_size);
  1573. int detect_src_top = max(0, rr.y - detect_size);
  1574. int detect_src_right = min(dst->width - 1, rr.x + w + detect_size * 2 - 1);
  1575. int detect_src_bottom = min(dst->height - 1, rr.y + h + detect_size * 2 - 1);
  1576. int detect_w = detect_src_right - detect_src_left + 1;
  1577. int detect_h = detect_src_bottom - detect_src_top + 1;
  1578. IplImage * timg = cvCreateImage(cvSize(detect_w, detect_h), IPL_DEPTH_8U, 1);
  1579. cvSetImageROI(dst, cvRect(detect_src_left, detect_src_top, detect_w, detect_h));
  1580. if (dst->nChannels == 3){
  1581. cvCvtColor(dst, timg, CV_BGR2GRAY);
  1582. cvThreshold(timg, timg, tembackcolor, 1, CV_THRESH_BINARY_INV);
  1583. }
  1584. else{
  1585. cvThreshold(dst, timg, tembackcolor, 1, CV_THRESH_BINARY_INV);
  1586. }
  1587. IplImage * iter = cvCreateImage(cvSize(detect_w + 1, detect_h + 1), IPL_DEPTH_32S, 1);
  1588. cvIntegral(timg, iter);
  1589. int max_gray_count = -1;
  1590. CvRect max_gray_count_rect;
  1591. for (int xx = detect_src_left - rr.x; xx <= detect_src_right - (rr.x + rr.width - 1); xx++)
  1592. {
  1593. for (int yy = detect_src_top - rr.y; yy <= detect_src_bottom - (rr.y + rr.height - 1); yy++)
  1594. {
  1595. int iter_left = max(0, detect_size + xx);
  1596. int iter_right = min(rr.width + detect_size * 2, detect_size + xx + rr.width);
  1597. int iter_top = max(0, detect_size + yy);
  1598. int iter_bottom = min(rr.height + detect_size * 2, detect_size + yy + rr.height);
  1599. 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);
  1600. if (gray_count > max_gray_count){
  1601. max_gray_count = gray_count;
  1602. max_gray_count_rect = cvRect(rr.x + xx, rr.y + yy, rr.width, rr.height);
  1603. }
  1604. }
  1605. }
  1606. if (max_gray_count > 0){
  1607. rr = max_gray_count_rect;
  1608. }
  1609. cvReleaseImage(&timg);
  1610. cvReleaseImage(&iter);
  1611. }
  1612. template<typename T1, typename T2>
  1613. T2 CResultReader::GetJiaoZhengResultPoint(T1& point)
  1614. {
  1615. float data[] = { point.x, point.y };
  1616. T2 resultPoint;
  1617. cv::Mat samples(1, 2, CV_32F, data);
  1618. cv::Mat results;
  1619. cv::Mat nresponse;
  1620. cv::Mat dist;
  1621. if (knn->isTrained()){
  1622. float response = knn->findNearest(samples, 1, results, nresponse, dist);
  1623. int idx = response;
  1624. if (0 <= idx&&idx < point_shijuan.size()){
  1625. cv::Point2f pm = point_muban[idx];
  1626. if (GetDistance(pm, point) < 50){
  1627. cv::Point2f ps0 = warpAffinePoint<cv::Point2f, cv::Point2f>(pm, &m_AffineTransform);
  1628. cv::Point2f ps1 = point_shijuan[idx];
  1629. float dx = ps1.x - ps0.x;
  1630. float dy = ps1.y - ps0.y;
  1631. cv::Point2f ps0_0 = warpAffinePoint<cv::Point2f, cv::Point2f>(Point2f(point.x, point.y), &m_AffineTransform);
  1632. resultPoint.x = ps0_0.x + dx;
  1633. resultPoint.y = ps0_0.y + dy;
  1634. }
  1635. else{
  1636. resultPoint = warpAffinePoint<cv::Point2f, T2>(Point2f(point.x, point.y), &m_AffineTransform);
  1637. }
  1638. }
  1639. else{
  1640. resultPoint = warpAffinePoint<cv::Point2f, T2>(Point2f(point.x, point.y), &m_AffineTransform);
  1641. }
  1642. }
  1643. else{
  1644. resultPoint = warpAffinePoint<cv::Point2f, T2>(Point2f(point.x, point.y), &m_AffineTransform);
  1645. }
  1646. return resultPoint;
  1647. }
  1648. int CResultReader::ReadQuestionScore(const ISCH_SCHEMA_PAGE &schemaPage)
  1649. {
  1650. IplImage t;
  1651. cvInitImageHeader(&t, cvSize(src->width, src->height), src->depth, src->nChannels, src->origin, src->align);
  1652. cvSetData(&t, src->imageData, src->widthStep);
  1653. IplImage * dst = &t;
  1654. omr_result->zhutuanti_result.resize(schemaPage.zhuguantis.size());
  1655. vector<ZHUGUANTI_RESULT> & zhutuanti_result_value = omr_result->zhutuanti_result;
  1656. for (int i = 0, score_count=0; i < schemaPage.zhuguantis.size(); i++){
  1657. const ISCH_SCHEMA_ZHUGUANTI& qs = schemaPage.zhuguantis[i];
  1658. double pscale = m_Scaler0;
  1659. int redcount[30];
  1660. int red_in_count[30];
  1661. float w = qs.width*pscale / qs.options.size();
  1662. float h = qs.height*pscale;
  1663. float dy = 0;// (ry - ly) / (float)qs.count;
  1664. BOOL hasSelect = FALSE;
  1665. double lx = m_AffineTransform.at<double>(0, 0)*(qs.centerx - qs.width / 2) + m_AffineTransform.at<double>(0, 1)*(qs.centery - qs.height / 2) + m_AffineTransform.at<double>(0, 2);
  1666. double rx = m_AffineTransform.at<double>(0, 0)*(qs.centerx + qs.width / 2) + m_AffineTransform.at<double>(0, 1)*(qs.centery + qs.height / 2) + m_AffineTransform.at<double>(0, 2);
  1667. int detect_l = lx;
  1668. int detect_r = rx;
  1669. double ly = m_AffineTransform.at<double>(1, 0)*(qs.centerx - qs.width / 2) + m_AffineTransform.at<double>(1, 1)*(qs.centery - qs.height / 2) + m_AffineTransform.at<double>(1, 2);
  1670. int detect_t = max(0, int(ly - h / 2 - 1));
  1671. int detect_b = min(dst->height - 1, int(ly + 3 * h / 2 - 1));
  1672. CvRect detect_rect = cvRect(detect_l, detect_t, detect_r - detect_l + 1, detect_b - detect_t + 1);
  1673. CvRect normal_rect = cvRect(lx, ly, rx - lx + 1, h);
  1674. 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());
  1675. zhutuanti_result_value[score_count].option.resize(qs.options.size());
  1676. for (int j = 0; j < qs.options.size(); j++){
  1677. 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);
  1678. SaveRect(rect, zhutuanti_result_value[score_count].option[j]);
  1679. }
  1680. float score = 0;
  1681. BOOL bx = FALSE;//是否判分小数位
  1682. BOOL bg = FALSE;//是否判分个位
  1683. BOOL bs = FALSE;//是否判分十位
  1684. {
  1685. //小数位
  1686. int red_area = 0;
  1687. int red_area_index = -1;
  1688. int red_area_index0 = -1;
  1689. for (int m = 0, n = 0; m < 1; m++, n++)
  1690. {
  1691. if (red_in_count[n] > red_area){ red_area = red_in_count[n]; red_area_index = m; red_area_index0 = n; }
  1692. }
  1693. if (red_area_index >= 0 && redcount[red_area_index0] > 25){
  1694. score = score + 0.5*(red_area_index + 1);
  1695. bx = TRUE;
  1696. }
  1697. }
  1698. {
  1699. //个位
  1700. int red_area = 0;
  1701. int red_area_index = -1;
  1702. int red_area_index0 = -1;
  1703. for (int m = 0, n = 2; m < 10 && n < qs.valid_option_count; m++, n++)
  1704. {
  1705. if (red_in_count[n] > red_area){ red_area = red_in_count[n]; red_area_index = m; red_area_index0 = n; }
  1706. }
  1707. if (red_area_index >= 0 && redcount[red_area_index0] > 25){
  1708. score = score + 1 * (red_area_index);
  1709. bg = TRUE;
  1710. }
  1711. }
  1712. {
  1713. //十位
  1714. int red_area = 0;
  1715. int red_area_index = -1;
  1716. int red_area_index0 = -1;
  1717. for (int m = 0, n = 13; m < 9 && n < qs.valid_option_count; m++, n++)
  1718. {
  1719. if (red_in_count[n] > red_area){ red_area = red_in_count[n]; red_area_index = m; red_area_index0 = n; }
  1720. }
  1721. if (red_area_index >= 0 && redcount[red_area_index0] > 25){
  1722. score = score + 10 * (red_area_index + 1);
  1723. bs = TRUE;
  1724. }
  1725. }
  1726. zhutuanti_result_value[score_count].question_score = score;
  1727. zhutuanti_result_value[score_count].question_state = (bx || bg || bs) ? OMR_QUESTION_STATE_NORMAL : OMR_QUESTION_STATE_LOUPI;
  1728. //zhutuanti_result_value[score_count].question_index = qs.question_index;
  1729. zhutuanti_result_value[score_count].question_code = qs.question_code;
  1730. zhutuanti_result_value[score_count].maxscore = 0;
  1731. zhutuanti_result_value[score_count].omr_question_type = ZHUTUANTI;
  1732. score_count++;
  1733. }
  1734. omr_result->tiankongti_result.resize(schemaPage.tiankongtis.size());
  1735. vector<TIANKONGTI_RESULT> & tiankongti_result_value = omr_result->tiankongti_result;
  1736. for (int i = 0, tiankong_count = 0; i < schemaPage.tiankongtis.size(); i++){
  1737. const ISCH_SCHEMA_TIANKONGTI& qs = schemaPage.tiankongtis[i];
  1738. double pscale = m_Scaler0;
  1739. float w = qs.width*pscale;
  1740. float h = qs.height*pscale;
  1741. double rx = m_AffineTransform.at<double>(0, 0)*(qs.centerx + qs.width / 2) + m_AffineTransform.at<double>(0, 1)*(qs.centery + qs.height / 2) + m_AffineTransform.at<double>(0, 2);
  1742. double ly = m_AffineTransform.at<double>(1, 0)*(qs.centerx - qs.width / 2) + m_AffineTransform.at<double>(1, 1)*(qs.centery - qs.height / 2) + m_AffineTransform.at<double>(1, 2);
  1743. for (int j = 0; j < 1; j++){
  1744. CvRect rect = cvRect((int)(rx - (j + 1)*w - 3), (int)(ly - 3), (int)(w + 6), (int)(h + 6));
  1745. SaveRect(rect, tiankongti_result_value[tiankong_count]);
  1746. cvSetImageROI(dst, rect);
  1747. int detect_l = max(0, rect.x - rect.width);
  1748. int detect_t = max(0, rect.y - rect.height);
  1749. int detect_r = min(dst->width - 1, rect.x + 2 * rect.width - 1);
  1750. int detect_b = min(dst->height - 1, rect.y + 2 * rect.height - 1);
  1751. CvRect rect_detect = cvRect(detect_l, detect_t, detect_r - detect_l + 1, detect_b - detect_t + 1);
  1752. int red_area = GetTianKongTiRedCount(dst, rect, rect_detect);
  1753. if (red_area > 25){
  1754. tiankongti_result_value[tiankong_count].isright = TRUE;
  1755. break;
  1756. }
  1757. else{
  1758. tiankongti_result_value[tiankong_count].isright = FALSE;
  1759. }
  1760. }
  1761. //tiankongti_result_value[tiankong_count].question_index = qs.question_index;
  1762. tiankongti_result_value[tiankong_count].question_code = qs.question_code;
  1763. tiankongti_result_value[tiankong_count].maxscore = 0;
  1764. tiankongti_result_value[tiankong_count].omr_question_type = TIANKONGTI;
  1765. tiankong_count++;
  1766. }
  1767. return IDF_SUCCESS;
  1768. }
  1769. int CResultReader::GetZhuGuanTiRedCount(IplImage * dst, const CvRect& rect, const CvRect& normal_rect, int * red_counts, int * red_in_counts, int count)
  1770. {
  1771. if (dst->nChannels != 3){ return 0; }
  1772. IplImage* red = NULL;
  1773. BOOL s = GetRedBinary(dst, rect, &red);
  1774. if (!s)return 0;
  1775. #define GET_ZHUGUANTI_REDCOUNT_DEBUG 0
  1776. #if GET_ZHUGUANTI_REDCOUNT_DEBUG
  1777. cvShowImage("sss", red);
  1778. cvWaitKey(0);
  1779. #endif
  1780. IplImage * temp = cvCloneImage(red);
  1781. CvMemStorage* storage = cvCreateMemStorage();
  1782. CvSeq* contours = NULL;
  1783. cvFindContours(temp, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));
  1784. int top = normal_rect.y - rect.y;
  1785. int bottom = normal_rect.y + normal_rect.height - 1 - rect.y;
  1786. for (CvContour * c = (CvContour *)contours; c != NULL; c = (CvContour *)c->h_next) {
  1787. CvRect b_rect = cvBoundingRect(c);
  1788. if (b_rect.y > bottom - 1 || b_rect.y + b_rect.height - 1 < top + 1){
  1789. cvDrawContours(red, (CvSeq *)c, cvScalar(0), cvScalar(0), 0, CV_FILLED, 8);
  1790. /***求出轮廓重心*****/
  1791. /*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);
  1792. cvDrawContours(temp,(CvSeq *)c,cvScalar(255),cvScalar(255),0,CV_FILLED,8);
  1793. int sum_x=0,sum_y=0,sum_count=0;
  1794. for (int y=b_rect.y,end_y=b_rect.y+b_rect.height,end_x=b_rect.x+b_rect.width;y<end_y;y++)
  1795. {
  1796. for (int x = b_rect.x;x<end_x;x++)
  1797. {
  1798. if(CV_IMAGE_ELEM(temp,unsigned char,y,x)){
  1799. sum_x+=x;
  1800. sum_y+=y;
  1801. sum_count++;
  1802. }
  1803. }
  1804. }
  1805. float avgx = sum_x/(float)sum_count;
  1806. float avgy = sum_y/(float)sum_count;
  1807. */
  1808. }
  1809. }
  1810. cvReleaseImage(&temp);
  1811. cvReleaseMemStorage(&storage);
  1812. #if GET_ZHUGUANTI_REDCOUNT_DEBUG
  1813. cvShowImage("sss", red);
  1814. cvWaitKey(0);
  1815. #endif
  1816. memset(red_counts, 0, sizeof(int)*count);
  1817. memset(red_in_counts, 0, sizeof(int)*count);
  1818. int w = red->width;
  1819. int h = red->height;
  1820. for (int x = 0; x < w; x++)
  1821. {
  1822. int option_index = (count - 1) - x*count / w;
  1823. for (int y = 0; y < h; y++)
  1824. {
  1825. if (CV_IMAGE_ELEM(red, unsigned char, y, x)){
  1826. red_counts[option_index]++;
  1827. if (y <= bottom - 1 && y >= top + 1){
  1828. red_in_counts[option_index]++;
  1829. }
  1830. }
  1831. }
  1832. }
  1833. cvReleaseImage(&red);
  1834. return IDF_SUCCESS;
  1835. }
  1836. int CResultReader::GetTianKongTiRedCount(IplImage * dst, const CvRect& rect_normal, const CvRect& rect_detect)
  1837. {
  1838. CvRect rect = cvGetImageROI(dst);
  1839. if (dst->nChannels != 3){ return 0; }
  1840. int w = rect_detect.width;
  1841. int h = rect_detect.height;
  1842. IplImage * red = NULL;
  1843. BOOL r = GetRedBinary(dst, rect_detect, &red);
  1844. if (!r)return 0;
  1845. vector<CvPoint2D32f> redPoints;
  1846. for (int y = 0; y < red->height; y++)
  1847. {
  1848. unsigned char * red_row_first = (unsigned char *)(red->imageData + (y*red->widthStep));
  1849. for (int x = 0; x < red->width; x++)
  1850. {
  1851. if (red_row_first[x]){
  1852. redPoints.push_back(cvPoint2D32f(x, y));
  1853. }
  1854. }
  1855. }
  1856. #define GET_TIANKONGTI_REDCOUNT_DEBUG 0
  1857. #if GET_TIANKONGTI_REDCOUNT_DEBUG
  1858. cvShowImage("sss", red);
  1859. cvWaitKey(0);
  1860. #endif
  1861. CvMemStorage * storage = cvCreateMemStorage();
  1862. CvSeq* contour = NULL;
  1863. int contours = cvFindContours(red, storage, &contour, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
  1864. int red_count = 0;
  1865. int normal_left = rect_normal.x - rect_detect.x;
  1866. int normal_top = rect_normal.y - rect_detect.y;
  1867. int normal_right = normal_left + rect_normal.width;
  1868. int normal_bottom = normal_top + rect_normal.height;
  1869. for (CvContour * c = (CvContour *)contour; c != NULL; c = (CvContour *)c->h_next){
  1870. float sum_x = 0;
  1871. float sum_y = 0;
  1872. int in_count = 0;
  1873. int area_c = 0;//轮廓在评分框内的点数
  1874. for (int i = 0; i < redPoints.size(); i++)
  1875. {
  1876. double distance = cvPointPolygonTest(c, redPoints[i], FALSE);
  1877. if (distance >= 0){
  1878. sum_x += redPoints[i].x;
  1879. sum_y += redPoints[i].y;
  1880. in_count++;
  1881. if (normal_left <= redPoints[i].x&&redPoints[i].x <= normal_right&&normal_top <= redPoints[i].y&&redPoints[i].y <= normal_bottom){
  1882. area_c++;
  1883. }
  1884. }
  1885. }
  1886. if (in_count == 0)continue;
  1887. if (area_c > 60){
  1888. red_count += in_count;
  1889. continue;
  1890. }
  1891. //重心位置
  1892. float avg_x = sum_x / in_count;
  1893. float avg_y = sum_y / in_count;
  1894. if (normal_left <= avg_x&&avg_x <= normal_right + 30 && normal_top <= avg_y&&avg_y <= normal_bottom){
  1895. red_count += in_count;
  1896. }
  1897. }
  1898. cvReleaseImage(&red);
  1899. cvReleaseMemStorage(&storage);
  1900. return red_count;
  1901. }
  1902. BOOL CResultReader::GetRedBinary(IplImage * dst, const CvRect& rect_detect, IplImage ** red_binary)
  1903. {
  1904. #define rename_image(img,new_name) IplImage * new_name = img; img = NULL;
  1905. if (dst == NULL || dst->nChannels != 3)return FALSE;
  1906. int w = rect_detect.width;
  1907. int h = rect_detect.height;
  1908. IplImage * hsv = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 3);
  1909. //存储灰度图像和二值化图像
  1910. IplImage * gray = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1);
  1911. IplImage * black = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1);
  1912. IplImage * black_dilate = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1);
  1913. //记录较浅一些的红色
  1914. IplImage * red_low = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1);
  1915. //记录较深一些的红色
  1916. IplImage * red_high = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1);
  1917. IplImage * red = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1);
  1918. cvSetImageROI(dst, rect_detect);
  1919. cvCvtColor(dst, hsv, CV_BGR2HSV);
  1920. cvCvtColor(dst, gray, CV_BGR2GRAY);
  1921. cvAdaptiveThreshold(gray, gray, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV, 9, 10.0);
  1922. rename_image(gray, binary);
  1923. #define HSV_VALUE_H hsv_row_first[hsv_offset]
  1924. #define HSV_VALUE_S hsv_row_first[hsv_offset+1]
  1925. #define HSV_VALUE_V hsv_row_first[hsv_offset+2]
  1926. const int hsv_v_valve = 255 * 50 / 100;
  1927. const int hsv_h_max_valve = 180 * 20 / 360;
  1928. const int hsv_h_min_valve = 180 * 315 / 360;
  1929. const int hsv_s_valve_1 = 255 * 13 / 100;
  1930. const int hsv_s_valve_2 = 255 * 23 / 100;
  1931. const int hsv_valve_high = 255 * (23 + 70) / 100;
  1932. const int hsv_valve_low = 255 * (13 + 60) / 100;
  1933. for (int y = 0; y < h; y++)
  1934. {
  1935. unsigned char * hsv_row_first = (unsigned char *)(hsv->imageData + y*hsv->widthStep);
  1936. unsigned char * red1_row_first = (unsigned char *)(red_low->imageData + y*red_low->widthStep);
  1937. unsigned char * red2_row_first = (unsigned char *)(red_high->imageData + y*red_high->widthStep);
  1938. unsigned char * binary_row_first = (unsigned char *)(binary->imageData + y*binary->widthStep);
  1939. unsigned char * black_row_first = (unsigned char *)(black->imageData + y*black->widthStep);
  1940. for (int x = 0, hsv_offset = 0; x < w; x++, hsv_offset += 3)
  1941. {
  1942. if (HSV_VALUE_V >= hsv_v_valve && (HSV_VALUE_H >= hsv_h_min_valve || HSV_VALUE_H <= hsv_h_max_valve)){
  1943. red1_row_first[x] = (HSV_VALUE_S >= hsv_s_valve_1 && (HSV_VALUE_S + HSV_VALUE_V) >= hsv_valve_low) ? 255 : 0;
  1944. red2_row_first[x] = (HSV_VALUE_S >= hsv_s_valve_2 && (HSV_VALUE_S + HSV_VALUE_V) >= hsv_valve_high) ? HSV_VALUE_S : 0;
  1945. }
  1946. else{
  1947. red1_row_first[x] = red2_row_first[x] = 0;
  1948. }
  1949. black_row_first[x] = (binary_row_first[x] && !red1_row_first[x]) ? 255 : 0;
  1950. }
  1951. }
  1952. cvThreshold(red_high, red_high, 0, 255, CV_THRESH_OTSU);
  1953. int an = 1;
  1954. IplConvKernel * element = cvCreateStructuringElementEx(an * 2 + 1, an * 2 + 1, an, an, CV_SHAPE_RECT, 0);//创建结构元素
  1955. cvDilate(binary, binary, element, 1);//膨胀图像
  1956. cvDilate(red_high, red_high, element, 1);//膨胀图像
  1957. cvDilate(black, black_dilate, element, 1);//膨胀图像
  1958. for (int y = 0; y < h; y++)
  1959. {
  1960. unsigned char * binary_row_first = (unsigned char *)(binary->imageData + y*binary->widthStep);
  1961. unsigned char * red1_row_first = (unsigned char *)(red_low->imageData + y*red_low->widthStep);
  1962. unsigned char * red2_row_first = (unsigned char *)(red_high->imageData + y*red_high->widthStep);
  1963. unsigned char * red_row_first = (unsigned char *)(red->imageData + y*red->widthStep);
  1964. unsigned char * black_dilate_row_first = (unsigned char *)(black_dilate->imageData + y*black_dilate->widthStep);
  1965. for (int x = 0; x < w; x++)
  1966. {
  1967. red_row_first[x] = (red1_row_first[x] && !black_dilate_row_first[x] && ((!binary_row_first[x]) || red2_row_first[x])) ? 255 : 0;
  1968. }
  1969. }
  1970. rename_image(red_high, red_dilate);
  1971. cvDilate(red, red_dilate, element, 2);//膨胀图像
  1972. for (int y = 0; y < h; y++)
  1973. {
  1974. unsigned char * red1_row_first = (unsigned char *)(red_low->imageData + y*red_low->widthStep);
  1975. unsigned char * red_row_first = (unsigned char *)(red->imageData + y*red->widthStep);
  1976. unsigned char * black_row_first = (unsigned char *)(black->imageData + y*black->widthStep);
  1977. unsigned char * red_dilate_row_first = (unsigned char *)(red_dilate->imageData + y*red_dilate->widthStep);
  1978. for (int x = 0; x < w; x++)
  1979. {
  1980. red_row_first[x] = (red_row_first[x] || (red_dilate_row_first[x] && (red1_row_first[x] && !black_row_first[x]))) ? 255 : 0;
  1981. }
  1982. }
  1983. cvDilate(red, red_dilate, element, 1);//膨胀图像
  1984. for (int y = 0; y < h; y++)
  1985. {
  1986. unsigned char * red_row_first = (unsigned char *)(red->imageData + y*red->widthStep);
  1987. unsigned char * black_row_first = (unsigned char *)(black->imageData + y*black->widthStep);
  1988. unsigned char * red_dilate_row_first = (unsigned char *)(red_dilate->imageData + y*red_dilate->widthStep);
  1989. for (int x = 0; x < w; x++)
  1990. {
  1991. if (!red_row_first[x] && black_row_first[x] && red_dilate_row_first[x]){
  1992. red_row_first[x] = 255;
  1993. }
  1994. }
  1995. }
  1996. cvReleaseStructuringElement(&element);
  1997. *red_binary = red;
  1998. //red1作为返回图像 不释放
  1999. cvReleaseImage(&hsv);
  2000. //cvReleaseImage(&gray);
  2001. cvReleaseImage(&binary);
  2002. cvReleaseImage(&black);
  2003. cvReleaseImage(&black_dilate);
  2004. cvReleaseImage(&red_low);
  2005. //cvReleaseImage(&red_high);
  2006. return TRUE;
  2007. }
  2008. }