OnLineCardPageIdentifier.cpp 162 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339
  1. #include "stdafx.h"
  2. #include "OnLineCardPageIdentifier.h"
  3. #include "OnLineCardSchemaStruct.h"
  4. #include "schema_struct.h"
  5. #include "schema_struct_auto.h"
  6. #include <iostream>
  7. #include <vector>
  8. #include <string>
  9. #include <sstream>
  10. #include <zxing\LuminanceSource.h>
  11. #include "GrayImageSource.h"
  12. #include <zxing\Exception.h>
  13. #include <zxing\qrcode\QRCodeReader.h>
  14. #include <zxing\qrcode\QRCodeReader.h>
  15. #include <zxing\BinaryBitmap.h>
  16. #include <zxing\common\GlobalHistogramBinarizer.h>
  17. #include <zxing\Binarizer.h>
  18. #include <zxing\qrcode\QRCodeReader.h>
  19. #include "schema_struct.h"
  20. #include <map>
  21. #include <..\zxinglib\zxing\ReaderException.h>
  22. #include "Util.h"
  23. #include "../lib/myqr/include/GetQRCode.h"
  24. #include "opencv2/opencv.hpp"
  25. #include <chrono>
  26. #include <ctime>
  27. #include "ParseQRInfo.h"
  28. #include "IdentifyArea.h"
  29. #include <atomic>
  30. #include <mutex>
  31. #define POSITION_JUGDMENT_THRESHOLD 0.6184074853897741
  32. std::atomic<int> g_examid_by_qr_code = 0;
  33. std::mutex g_mtx_examid;
  34. extern std::string g_appFilePathName;
  35. static std::string GetExePath()
  36. {
  37. HMODULE module = GetModuleHandle(0);
  38. char pFileName[MAX_PATH + 2] = { 0 };
  39. GetModuleFileNameA(module, pFileName, MAX_PATH);
  40. std::string csFullPath(pFileName);
  41. std::size_t nPos = csFullPath.find_last_of('\\');
  42. if (nPos == std::string::npos)
  43. return "";
  44. else
  45. return csFullPath.substr(0, nPos);
  46. }
  47. /********************************************************
  48. * @function :
  49. * @brief : 红色分析判断的客户端交互接口(阶段1:实现红色像素的数量统计 阶段2:实现红色的形状判断 目前只实现阶段1
  50. * @input : Mat img_input; // 切割好的打分框区域 精准区域
  51. int cols; // 该打分框的个数
  52. int type; // 打分框所属(非在线模板解答0 非在线模板填空1 在线模板解答2 在线模板填空3 )
  53. int mutil: // 是否是组合型包含(个位+十位) 打分框
  54. int * a_res; // 存放结果的数组
  55. int len; // a_res的长度 len应该等于cols
  56. * @output : int ret; // 0: succ 1: faild 2: img.empty||img.error
  57. * @return : int ret;
  58. * @author : Duste 2020/03/27 10:07
  59. * @History :
  60. *********************************************************/
  61. __declspec(dllimport) int api_red_check_analysis(cv::Mat&img, int cols, int type, int mutil, int * arr_result, int arr_len);
  62. /********************************************************
  63. * @function :
  64. * @brief : DTK的定位点查找
  65. * @input : @见函数说明 给定图像+模板定位点位置信息,
  66. * @output :
  67. * @return : int,(0:succ) (-1:input error) (-2:img.empty||img type.error) (-3:not found)
  68. * @author : Duste 2020/07/02 15:33
  69. * @History :
  70. *********************************************************/
  71. int api_location_anchor_points(const cv::Mat&img_gray, // 输入的灰度图像
  72. const std::vector<cv::Rect>&vec_lcpts, // json内的定位点信息
  73. const cv::Size&mb_size, // json内模板图像的宽高
  74. std::vector<cv::Rect>&vec_tops, // 接受找到的上面三个定位点 下标访问
  75. std::vector<cv::Rect>&vec_bottoms, // 接受找到的下面的两个定位点 下标访问
  76. std::vector<int>&vec_len, // 解决不同版本内存权限问题
  77. int&dir, // 接受识别到的本图像的方向(0123-上下左右)
  78. int top_number, // 知心慧学 top_number=3或4 在线模板 top_number=3
  79. int need_bottom // 是否需要查找bottom定位点
  80. );// Vec_lcpts: json内的两页内所有的定位点的矩形信息合集
  81. #if _DEBUG
  82. #pragma comment(lib,"../lib/myqr/debug/GetQR.lib")
  83. #pragma comment(lib,"../Win32/Debug/client_interactive_api_ttpdd.lib")
  84. #pragma comment(lib,"../Win32/Debug/client_interactive_api_d.lib")
  85. #pragma comment(lib,"../Win32/Debug/client_interactive_api_code_d.lib")
  86. #else
  87. #pragma comment(lib,"../lib/myqr/Release/GetQR.lib")
  88. #pragma comment(lib,"../Win32/Release/client_interactive_api_ttpd.lib")
  89. #pragma comment(lib,"../Win32/Release/client_interactive_api.lib")
  90. #pragma comment(lib,"../Win32/Release/client_interactive_api_code.lib")
  91. #endif
  92. using namespace cv;
  93. using namespace std;
  94. using namespace zxing;
  95. namespace OnLineCard{
  96. enum SelectType{
  97. //未选中
  98. UNSELECT,
  99. //不确定
  100. UNCERTAIN,
  101. //选中
  102. SELECTED
  103. };
  104. #define MAX_ITEM 64
  105. enum
  106. {
  107. JIEDATITYPE = 0,
  108. TIANKONGTITYPE = 1,
  109. };
  110. void SetTBLR(SchemaQuestionScore& score)
  111. {
  112. score.lt.x = score.lb.x = (int)(0.5 + score.centerx - score.width / 2.0);
  113. score.rt.x = score.rb.x = (int)(0.5 + score.centerx + score.width / 2.0);
  114. score.lt.y = score.rt.y = (int)(0.5 + score.centery - score.height / 2.0);
  115. score.lb.y = score.rb.y = (int)(0.5 + score.centery + score.height / 2.0);
  116. }
  117. COnLineCardPageIdentifier::COnLineCardPageIdentifier()
  118. {
  119. HMODULE module = GetModuleHandle(0);
  120. char pFileName[MAX_PATH + 2] = { 0 };
  121. GetModuleFileNameA(module, pFileName, MAX_PATH);
  122. std::string strPath = pFileName;
  123. int pos = strPath.find_last_of('\\', strPath.length());
  124. strPath = strPath.substr(0, pos) + "\\..\\config.ini";
  125. int nType = GetPrivateProfileIntA("USER", "algorithm_boption", 1, strPath.c_str());
  126. m_nBxuanxiang = (nType == 1);
  127. m_pTemplate = nullptr;
  128. src = NULL;
  129. feedDirection = ROTATE_0;
  130. m_strQrClass = "";
  131. m_bUseQr = false;
  132. }
  133. COnLineCardPageIdentifier::~COnLineCardPageIdentifier()
  134. {
  135. }
  136. // 识别
  137. int COnLineCardPageIdentifier::Identify()
  138. {
  139. try{
  140. int r = Identify_impl();
  141. if (r == identify::result::IDF_SUCCESS){
  142. omr_result->identified = TRUE;
  143. omr_result->identify_msg = "识别成功";
  144. return r;
  145. }
  146. }catch (std::exception &e){
  147. //LOGI("COnLineCardPageIdentifier::Identify 异常");
  148. return identify::result::IDF_FAILURE;
  149. }
  150. return identify::result::IDF_CANNOT_MATCH_TEMPLATE;
  151. }
  152. void COnLineCardPageIdentifier::SetScanMode(int type)
  153. {
  154. m_scantype = type;
  155. }
  156. void COnLineCardPageIdentifier::SetUseQr(std::string strQr, bool bUse)
  157. {
  158. m_bUseQr = bUse;
  159. m_strQrClass = strQr;
  160. }
  161. void COnLineCardPageIdentifier::SetOnlineScanType(int nOnlineScanType)
  162. {
  163. m_nOnlineScanType = nOnlineScanType;
  164. }
  165. void COnLineCardPageIdentifier::SetPaperMode(int mode)
  166. {
  167. m_paper_mode = mode;
  168. }
  169. void COnLineCardPageIdentifier::SetIdentiforMode(int subject, int mode)
  170. {
  171. m_subjectMode = subject;
  172. m_identiforMode = mode;
  173. }
  174. #define ROUND_SCALE(x) ((int)(x*scale+0.5))
  175. #define ROUND_SCALE_ARRAY(_dst,_src,count) \
  176. for (int i=0;i<count;i++)\
  177. {\
  178. _dst[i]=((int)(_src[i]*scale+0.5));\
  179. }
  180. void COnLineCardPageIdentifier::myscale_shema_param0(const schema_const_param& default_schema_const_param, schema_const_param& schema_param, double scale){
  181. schema_param.main_locate_point = default_schema_const_param.main_locate_point;
  182. ROUND_SCALE_ARRAY(schema_param.minw, default_schema_const_param.minw, 4);
  183. ROUND_SCALE_ARRAY(schema_param.maxw, default_schema_const_param.maxw, 4);
  184. ROUND_SCALE_ARRAY(schema_param.minh, default_schema_const_param.minh, 4);
  185. ROUND_SCALE_ARRAY(schema_param.maxh, default_schema_const_param.maxh, 4);
  186. }
  187. //旋转指定区域
  188. int COnLineCardPageIdentifier::xuanzhuan(IplImage * src0, IplImage * &dst_img, CvRect myRect)
  189. {
  190. cvSetImageROI(src0, myRect);
  191. IplImage* result = cvCreateImage(cvSize(myRect.width, myRect.height), src0->depth, src0->nChannels);
  192. cvCopy(src0, result, NULL);
  193. cvResetImageROI(src0);
  194. dst_img = cvCreateImage(cvSize(myRect.height, myRect.width), src0->depth, src0->nChannels);
  195. cvTranspose(result, dst_img);
  196. cvFlip(dst_img, NULL, 1);
  197. cvReleaseImage(&result);
  198. return identify::result::IDF_SUCCESS;
  199. }
  200. inline int get_distance(CvPoint2D32f p1, CvPoint2D32f p2){
  201. double dy = p2.y - p1.y;
  202. double dx = p2.x - p1.x;
  203. return static_cast<int>(sqrt(dx*dx + dy*dy));
  204. }
  205. // 纠偏后的新坐标点
  206. CvPoint2D32f get_new_point(CvPoint2D32f ptOld, int iWidth, int iHight, float thir)
  207. {
  208. // 转图像中心坐标系
  209. CvPoint2D32f ptNew, ptNew_, ptOld_;
  210. CvPoint2D32f ptMid = cvPoint2D32f(iWidth / 2.0, iHight / 2.0);
  211. ptOld_.x = ptOld.x - ptMid.x;
  212. ptOld_.y = -(ptOld.y - ptMid.y);
  213. float thetia = atan2(float(ptOld_.y), float(ptOld_.x));
  214. float angleOld = static_cast<int>( thetia * 180.0 / CV_PI);
  215. float angleNew = angleOld - thir;
  216. double dx = cos(angleNew*CV_PI / 180.0)*ptOld_.y / sin(angleOld*CV_PI / 180.0);
  217. double dy = sin(angleNew*CV_PI / 180.0)*ptOld_.y / sin(angleOld*CV_PI / 180.0);
  218. ptNew_.x = dx > 0 ? (dx + 0.5) : (dx - 0.5);
  219. ptNew_.y = dy > 0 ? (dy + 0.5) : (dy - 0.5);
  220. // 转回原坐标系坐标
  221. // 这里需要重新计算 中心点坐标(计算四个顶点后计算外接矩形再确定中心点)
  222. // 这里简化处理 因为只需要处理 90,180,270,等固定角度旋转
  223. if (90 == abs(thir) || 270 == abs(thir))
  224. ptMid = cvPoint2D32f(iHight / 2.0, iWidth / 2.0);
  225. ptNew.x = ptNew_.x + ptMid.x;
  226. ptNew.y = ptMid.y - ptNew_.y;
  227. return ptNew;
  228. }
  229. bool sort_locate_point_by_x_pt2f(const CvPoint2D32f c1, const CvPoint2D32f c2)
  230. {
  231. return c1.x < c2.x;
  232. }
  233. inline void sort_point_list(CvPoint2D32f * points_src){
  234. int max_y = std::max(std::max(points_src[0].y, points_src[1].y), points_src[2].y);
  235. vector<CvPoint2D32f> vec_one, vec_two;
  236. for (int i = 0; i < 3; i++)
  237. {
  238. CvPoint2D32f tmp = points_src[i];
  239. if (tmp.y > max_y / 2)
  240. vec_two.push_back(tmp);
  241. else
  242. vec_one.push_back(tmp);
  243. }
  244. std::sort(vec_one.begin(), vec_one.end(), sort_locate_point_by_x_pt2f);
  245. for (std::size_t i = 0; i < vec_one.size(); i++)
  246. points_src[i] = vec_one[i];
  247. points_src[vec_one.size()] = vec_two[0];
  248. return;
  249. }
  250. inline cv::Mat IplImageToMat(const IplImage* image, bool copyData = false)
  251. {
  252. if (!image)
  253. return cv::Mat();
  254. int imageDepth = IPL2CV_DEPTH(image->depth);
  255. int type = CV_MAKETYPE(imageDepth, image->nChannels);
  256. cv::Mat ret(image->height, image->width, type, image->imageData, image->widthStep);
  257. return copyData ? ret.clone() : ret;
  258. }
  259. int COnLineCardPageIdentifier::JiaoZheng_20200418_first(IplImage * src0_, IplImage * &dst_img,
  260. const vector<CvRect> & top_locate_point_list, const vector<CvRect> & bottom_locate_point_list, const vector<CvRect> & word_location_point_list,
  261. int dir)
  262. {
  263. // printf("线程:%s JiaoZheng_20200418_first1 \n", std::to_string(GetCurrentThreadId()).c_str());
  264. int bottom_id = 0;
  265. if (3 == dir)
  266. bottom_id = 1;
  267. CvPoint2D32f points_src[3] = {
  268. cvPoint2D32f(top_locate_point_list[0].x + top_locate_point_list[0].width / 2.0, top_locate_point_list[0].y + top_locate_point_list[0].height / 2.0),
  269. cvPoint2D32f(top_locate_point_list[top_locate_point_list.size() - 1].x + top_locate_point_list[top_locate_point_list.size() - 1].width / 2.0, top_locate_point_list[top_locate_point_list.size() - 1].y + top_locate_point_list[top_locate_point_list.size() - 1].height / 2.0),
  270. cvPoint2D32f(bottom_locate_point_list[bottom_id].x + bottom_locate_point_list[bottom_id].width / 2.0, bottom_locate_point_list[bottom_id].y + bottom_locate_point_list[bottom_id].height / 2.0)
  271. };
  272. IplImage * src0 = nullptr;
  273. // printf("线程:%s JiaoZheng_20200418_first2 \n", std::to_string(GetCurrentThreadId()).c_str());
  274. try{
  275. src0 = cvCloneImage(src0_);
  276. }
  277. catch (cv::Exception&e){
  278. // printf("线程:%s cvCloneImage %s\n", std::to_string(GetCurrentThreadId()).c_str(), e.what());
  279. }
  280. // printf("线程:%s JiaoZheng_20200418_first3 \n", std::to_string(GetCurrentThreadId()).c_str());
  281. // 0:上 旋转0度 1:下 旋转180度 2:左 旋转90度 3:右 旋转270度 如果不对请自行调整
  282. CvPoint2D32f points_src_rotate[3] = { points_src[0], points_src[1], points_src[2] };
  283. // printf("线程:%s JiaoZheng_20200418_first cvCreateImage dir=%d %d %d %d %d \n", std::to_string(GetCurrentThreadId()).c_str(), dir, src0->width, src0->height, src0->depth, src0->nChannels);
  284. float angle = 0.0;
  285. if (0 == dir) {
  286. angle = 0.0;
  287. dst_img = cvCreateImage(cvSize(src0->width, src0->height), src0->depth, src0->nChannels);
  288. }
  289. else if (1 == dir){
  290. angle = 180;
  291. //cvFlip(src0,src0,1);
  292. dst_img = cvCreateImage(cvSize(src0->width, src0->height), src0->depth, src0->nChannels);
  293. }
  294. else if (2 == dir) {
  295. angle = 90;
  296. dst_img = cvCreateImage(cvSize(src0->height, src0->width), src0->depth, src0->nChannels);
  297. }
  298. else if (3 == dir) {
  299. angle = 270;
  300. dst_img = cvCreateImage(cvSize(src0->height, src0->width), src0->depth, src0->nChannels);
  301. }
  302. else
  303. return identify::result::IDF_FAILURE;
  304. // printf("线程:%s JiaoZheng_20200418_first cvCreateImage end \n", std::to_string(GetCurrentThreadId()).c_str());
  305. if (angle > 1.0){
  306. for (int i = 0; i < 3; i++){
  307. points_src_rotate[i] = get_new_point(points_src_rotate[i], src0->width, src0->height, angle);
  308. }
  309. }
  310. // printf("线程:%s JiaoZheng_20200418_first4 \n", std::to_string(GetCurrentThreadId()).c_str());
  311. CvPoint2D32f points_dst[3];
  312. for (int i = 0; i < 3; i++){
  313. CvPoint2D32f pt_src_tmp = points_src_rotate[i];
  314. int nearst_id = -1;
  315. int nearst_distance = 100000000;
  316. for (std::size_t j = 0; j < word_location_point_list.size(); j++){
  317. CvPoint2D32f pt_dst_tmp = cvPoint2D32f(word_location_point_list[j].x + word_location_point_list[j].width / 2.0, word_location_point_list[j].y + word_location_point_list[j].height / 2.0);
  318. int distance = get_distance(pt_src_tmp, pt_dst_tmp);
  319. if (distance < nearst_distance){
  320. nearst_distance = distance;
  321. nearst_id = j;
  322. }
  323. }
  324. if (-1 == nearst_id)
  325. return identify::result::IDF_FAILURE;
  326. points_dst[i] = cvPoint2D32f(word_location_point_list[nearst_id].x + word_location_point_list[nearst_id].width / 2.0, word_location_point_list[nearst_id].y + word_location_point_list[nearst_id].height / 2.0);;
  327. }
  328. // printf("线程:%s JiaoZheng_20200418_first5 \n", std::to_string(GetCurrentThreadId()).c_str());
  329. CvMat * warp_mat = cvCreateMat(2, 3, CV_32FC1);
  330. cvGetAffineTransform(points_src, points_dst, warp_mat);
  331. cvWarpAffine(src0, dst_img, warp_mat, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvScalarAll(255));
  332. cvReleaseMat(&warp_mat);
  333. #if _DEBUG
  334. cvSaveImage("D:\\show\\1.png", src0);
  335. cvSaveImage("D:\\show\\2.png", dst_img);
  336. #endif
  337. cvReleaseImage(&src0);
  338. // printf("线程:%s JiaoZheng_20200418_first6 \n", std::to_string(GetCurrentThreadId()).c_str());
  339. return identify::result::IDF_SUCCESS;
  340. }
  341. int COnLineCardPageIdentifier::JiaoZheng_20200418_second_four(IplImage * src0_, IplImage * &dst_img,
  342. const vector<CvRect> & top_locate_point_list, const vector<CvRect> & bottom_locate_point_list, const vector<CvRect> & word_location_point_list,
  343. int dir)
  344. {
  345. //CV_Assert(top_locate_point_list.size()>2);
  346. //CV_Assert(bottom_locate_point_list.size());
  347. CvPoint2D32f points_src[4] = {
  348. cvPoint2D32f(top_locate_point_list[0].x + top_locate_point_list[0].width / 2.0, top_locate_point_list[0].y + top_locate_point_list[0].height / 2.0),
  349. cvPoint2D32f(top_locate_point_list[top_locate_point_list.size() - 1].x + top_locate_point_list[top_locate_point_list.size() - 1].width / 2.0, top_locate_point_list[top_locate_point_list.size() - 1].y + top_locate_point_list[top_locate_point_list.size() - 1].height / 2.0),
  350. cvPoint2D32f(bottom_locate_point_list[0].x + bottom_locate_point_list[0].width / 2.0, bottom_locate_point_list[0].y + bottom_locate_point_list[0].height / 2.0),
  351. cvPoint2D32f(bottom_locate_point_list[1].x + bottom_locate_point_list[1].width / 2.0, bottom_locate_point_list[1].y + bottom_locate_point_list[1].height / 2.0)
  352. };
  353. IplImage * src0 = cvCloneImage(src0_);
  354. // 0:上 旋转0度 1:下 旋转180度 2:左 旋转90度 3:右 旋转270度 如果不对请自行调整
  355. CvPoint2D32f points_src_rotate[4] = { points_src[0], points_src[1], points_src[2], points_src[3] };
  356. float angle = 0.0;
  357. if (0 == dir) {
  358. angle = 0.0;
  359. dst_img = cvCreateImage(cvSize(src0->width, src0->height), src0->depth, src0->nChannels);
  360. }
  361. else if (1 == dir){
  362. angle = 180;
  363. //cvFlip(src0,src0,1);
  364. dst_img = cvCreateImage(cvSize(src0->width, src0->height), src0->depth, src0->nChannels);
  365. }
  366. else if (2 == dir) {
  367. angle = 90;
  368. dst_img = cvCreateImage(cvSize(src0->height, src0->width), src0->depth, src0->nChannels);
  369. }
  370. else if (3 == dir) {
  371. angle = 270;
  372. dst_img = cvCreateImage(cvSize(src0->height, src0->width), src0->depth, src0->nChannels);
  373. }
  374. else
  375. return identify::result::IDF_FAILURE;
  376. if (angle > 1.0){
  377. for (int i = 0; i < 4; i++){
  378. points_src_rotate[i] = get_new_point(points_src_rotate[i], src0->width, src0->height, angle);
  379. }
  380. }
  381. CvPoint2D32f points_dst[4];
  382. for (std::size_t i = 0; i < 4; i++){
  383. CvPoint2D32f pt_src_tmp = points_src_rotate[i];
  384. int nearst_id = -1;
  385. int nearst_distance = 100000000;
  386. for (std::size_t j = 0; j < word_location_point_list.size(); j++){
  387. CvPoint2D32f pt_dst_tmp = cvPoint2D32f(word_location_point_list[j].x + word_location_point_list[j].width / 2.0, word_location_point_list[j].y + word_location_point_list[j].height / 2.0);
  388. int distance = get_distance(pt_src_tmp, pt_dst_tmp);
  389. if (distance < nearst_distance){
  390. nearst_distance = distance;
  391. nearst_id = j;
  392. }
  393. }
  394. if (-1 == nearst_id)
  395. return identify::result::IDF_FAILURE;
  396. points_dst[i] = cvPoint2D32f(word_location_point_list[nearst_id].x + word_location_point_list[nearst_id].width / 2.0, word_location_point_list[nearst_id].y + word_location_point_list[nearst_id].height / 2.0);;
  397. }
  398. Point2f pts[4];
  399. for (int i = 0; i < 4; i++)
  400. pts[i] = Point2f(points_src[i].x, points_src[i].y);
  401. Point2f ptd[4];
  402. for (int i = 0; i < 4; i++)
  403. ptd[i] = Point2f(points_dst[i].x, points_dst[i].y);
  404. cv::Mat warp_mat(cv::Size(3, 3), CV_32FC1);
  405. warp_mat = getPerspectiveTransform(pts, ptd);
  406. CvMat b = warp_mat;
  407. cvWarpPerspective(src0_, dst_img, &b, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvScalarAll(255));
  408. #if _DEBUG
  409. cvSaveImage("D:\\show\\1.png", src0);
  410. cvSaveImage("D:\\show\\2.png", dst_img);
  411. #endif
  412. cvReleaseImage(&src0);
  413. return identify::result::IDF_SUCCESS;
  414. }
  415. int COnLineCardPageIdentifier::JiaoZheng_20200418_second_five(IplImage * src0_, IplImage * &dst_img,
  416. const vector<CvRect> & top_locate_point_list, const vector<CvRect> & bottom_locate_point_list, const vector<CvRect> & word_location_point_list,
  417. int dir)
  418. {
  419. //CV_Assert(top_locate_point_list.size()>2);
  420. //CV_Assert(bottom_locate_point_list.size());
  421. CvPoint2D32f points_src[5] = {
  422. cvPoint2D32f(top_locate_point_list[0].x + top_locate_point_list[0].width / 2.0, top_locate_point_list[0].y + top_locate_point_list[0].height / 2.0),
  423. cvPoint2D32f(top_locate_point_list[1].x + top_locate_point_list[1].width / 2.0, top_locate_point_list[1].y + top_locate_point_list[1].height / 2.0),
  424. cvPoint2D32f(top_locate_point_list[top_locate_point_list.size() - 1].x + top_locate_point_list[top_locate_point_list.size() - 1].width / 2.0, top_locate_point_list[top_locate_point_list.size() - 1].y + top_locate_point_list[top_locate_point_list.size() - 1].height / 2.0),
  425. cvPoint2D32f(bottom_locate_point_list[0].x + bottom_locate_point_list[0].width / 2.0, bottom_locate_point_list[0].y + bottom_locate_point_list[0].height / 2.0),
  426. cvPoint2D32f(bottom_locate_point_list[1].x + bottom_locate_point_list[1].width / 2.0, bottom_locate_point_list[1].y + bottom_locate_point_list[1].height / 2.0)
  427. };
  428. IplImage * src0 = cvCloneImage(src0_);
  429. // 0:上 旋转0度 1:下 旋转180度 2:左 旋转90度 3:右 旋转270度 如果不对请自行调整
  430. CvPoint2D32f points_src_rotate[5] = { points_src[0], points_src[1], points_src[2], points_src[3], points_src[4] };
  431. float angle = 0.0;
  432. if (0 == dir) {
  433. angle = 0.0;
  434. dst_img = cvCreateImage(cvSize(src0->width, src0->height), src0->depth, src0->nChannels);
  435. }
  436. else if (1 == dir){
  437. angle = 180;
  438. //cvFlip(src0,src0,1);
  439. dst_img = cvCreateImage(cvSize(src0->width, src0->height), src0->depth, src0->nChannels);
  440. }
  441. else if (2 == dir) {
  442. angle = 90;
  443. dst_img = cvCreateImage(cvSize(src0->height, src0->width), src0->depth, src0->nChannels);
  444. }
  445. else if (3 == dir) {
  446. angle = 270;
  447. dst_img = cvCreateImage(cvSize(src0->height, src0->width), src0->depth, src0->nChannels);
  448. }
  449. else
  450. return identify::result::IDF_FAILURE;
  451. if (angle > 1.0){
  452. for (int i = 0; i < 5; i++){
  453. points_src_rotate[i] = get_new_point(points_src_rotate[i], src0->width, src0->height, angle);
  454. }
  455. }
  456. CvPoint2D32f points_dst[5];
  457. for (std::size_t i = 0; i < 5; i++){
  458. CvPoint2D32f pt_src_tmp = points_src_rotate[i];
  459. int nearst_id = -1;
  460. int nearst_distance = 100000000;
  461. for (std::size_t j = 0; j < word_location_point_list.size(); j++){
  462. CvPoint2D32f pt_dst_tmp = cvPoint2D32f(word_location_point_list[j].x + word_location_point_list[j].width / 2.0, word_location_point_list[j].y + word_location_point_list[j].height / 2.0);
  463. int distance = get_distance(pt_src_tmp, pt_dst_tmp);
  464. if (distance < nearst_distance){
  465. nearst_distance = distance;
  466. nearst_id = j;
  467. }
  468. }
  469. if (-1 == nearst_id)
  470. return identify::result::IDF_FAILURE;
  471. points_dst[i] = cvPoint2D32f(word_location_point_list[nearst_id].x + word_location_point_list[nearst_id].width / 2.0, word_location_point_list[nearst_id].y + word_location_point_list[nearst_id].height / 2.0);;
  472. }
  473. Point2f pts[5];
  474. for (int i = 0; i < 5; i++)
  475. pts[i] = Point2f(points_src[i].x, points_src[i].y);
  476. Point2f ptd[5];
  477. for (int i = 0; i < 5; i++)
  478. ptd[i] = Point2f(points_dst[i].x, points_dst[i].y);
  479. cv::Mat warp_mat(cv::Size(3, 3), CV_32FC1);
  480. warp_mat = getPerspectiveTransform(pts, ptd);
  481. CvMat b = warp_mat;
  482. cvWarpPerspective(src0_, dst_img, &b, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvScalarAll(255));
  483. #if _DEBUG
  484. cvSaveImage("D:\\show\\1.png", src0);
  485. cvSaveImage("D:\\show\\2.png", dst_img);
  486. #endif
  487. cvReleaseImage(&src0);
  488. return identify::result::IDF_SUCCESS;
  489. }
  490. int COnLineCardPageIdentifier::JiaoZheng_20200418(IplImage * src0, IplImage * &dst_img,
  491. const vector<CvRect> & top_locate_point_list, const vector<CvRect> & bottom_locate_point_list, const vector<CvRect> & word_location_point_list,
  492. int dir, double scale_x, double scale_y, int word_w, int word_h)
  493. {
  494. int len_l = top_locate_point_list.size();
  495. if (len_l != 3 || bottom_locate_point_list.size() != 2)
  496. return identify::result::IDF_FAILURE;
  497. // 中心点
  498. CvPoint2D32f points_src_[3] = {
  499. cvPoint2D32f(top_locate_point_list[0].x + top_locate_point_list[0].width / 2.0, top_locate_point_list[0].y + top_locate_point_list[0].height / 2.0),
  500. cvPoint2D32f(top_locate_point_list[len_l - 1].x + top_locate_point_list[len_l - 1].width / 2.0, top_locate_point_list[len_l - 1].y + top_locate_point_list[len_l - 1].height / 2.0),
  501. cvPoint2D32f(bottom_locate_point_list[0].x + bottom_locate_point_list[0].width / 2.0, bottom_locate_point_list[0].y + bottom_locate_point_list[0].height / 2.0)
  502. };
  503. cv::Size location_size[3] = {
  504. cvSize(top_locate_point_list[0].width, top_locate_point_list[0].height),
  505. cvSize(top_locate_point_list[len_l - 1].width, top_locate_point_list[len_l - 1].height),
  506. cvSize(bottom_locate_point_list[0].width, bottom_locate_point_list[0].height)
  507. };
  508. // 0:上 旋转0度 1:下 旋转180度 2:左 旋转90度 3:右 旋转270度 如果不对请自行调整
  509. CvPoint2D32f points_src_rotate[3] = { points_src_[0], points_src_[1], points_src_[2] };
  510. float angle = 0.0;
  511. int use_w = src0->width;
  512. int use_h = src0->height;
  513. if (0 == dir) {
  514. angle = 0.0;
  515. }
  516. else if (1 == dir){
  517. angle = 180;
  518. }
  519. else if (2 == dir) {
  520. angle = 90;
  521. swap(use_w, use_h);
  522. for (int i = 0; i < 3; i++)
  523. swap(location_size[i].width, location_size[i].height);
  524. }
  525. else if (3 == dir) {
  526. angle = 270;
  527. swap(use_w, use_h);
  528. for (int i = 0; i < 3; i++)
  529. swap(location_size[i].width, location_size[i].height);
  530. }
  531. else
  532. return identify::result::IDF_FAILURE;
  533. if (angle > 1.0){
  534. for (int i = 0; i < 3; i++){
  535. points_src_rotate[i] = get_new_point(points_src_rotate[i], src0->width, src0->height, angle);
  536. }
  537. }
  538. // 按照从左到右 从上到下 排序
  539. sort_point_list(points_src_rotate);
  540. // 推算边缘点
  541. CvPoint2D32f points_src[3] = {
  542. cvPoint2D32f(points_src_rotate[0].x - (location_size[0].width / 2.0 + 0.55), top_locate_point_list[0].y - (location_size[0].height / 2.0 + 0.55)),
  543. cvPoint2D32f(points_src_rotate[1].x + (location_size[1].width / 2.0 + 0.55), top_locate_point_list[1].y - (location_size[1].height / 2.0 + 0.55)),
  544. cvPoint2D32f(points_src_rotate[2].x - (location_size[2].width / 2.0 + 0.55), top_locate_point_list[2].y + (location_size[2].height / 2.0 + 0.55))
  545. };
  546. // 寻找json数据的对应定位点坐标
  547. CvPoint2D32f points_dst_[3]; // 中心点
  548. CvPoint2D32f points_dst[3]; // 边缘点
  549. for (std::size_t i = 0; i < 3; i++){
  550. CvPoint2D32f pt_src_tmp = points_src_rotate[i];
  551. int nearst_id = -1;
  552. int nearst_distance = 100000000;
  553. for (std::size_t j = 0; j < word_location_point_list.size(); j++){
  554. CvRect rc_tmp;
  555. rc_tmp.x = word_location_point_list[j].x*scale_x + 0.55;
  556. rc_tmp.y = word_location_point_list[j].y*scale_y + 0.55;
  557. rc_tmp.width = word_location_point_list[j].width*scale_x + 0.55;
  558. rc_tmp.height = word_location_point_list[j].height*scale_y + 0.55;
  559. CvPoint2D32f pt_dst_tmp = cvPoint2D32f(rc_tmp.x + rc_tmp.width / 2.0, rc_tmp.y + rc_tmp.height / 2.0);
  560. int distance = get_distance(pt_src_tmp, pt_dst_tmp);
  561. if (distance < nearst_distance){
  562. nearst_distance = distance;
  563. nearst_id = j;
  564. }
  565. }
  566. if (-1 == nearst_id)
  567. return identify::result::IDF_FAILURE;
  568. points_dst_[i] = cvPoint2D32f(word_location_point_list[nearst_id].x + word_location_point_list[nearst_id].width / 2.0, word_location_point_list[nearst_id].y + word_location_point_list[nearst_id].height / 2.0);;
  569. if (0 == i)
  570. points_dst[i] = cvPoint2D32f(word_location_point_list[nearst_id].x, word_location_point_list[nearst_id].y);
  571. else if (1 == i)
  572. points_dst[i] = cvPoint2D32f(word_location_point_list[nearst_id].x + word_location_point_list[nearst_id].width, word_location_point_list[nearst_id].y);
  573. else
  574. points_dst[i] = cvPoint2D32f(word_location_point_list[nearst_id].x, word_location_point_list[nearst_id].y + word_location_point_list[nearst_id].height);
  575. }
  576. #define GET_SCALE 1
  577. #if GET_SCALE
  578. int len = 3;
  579. int dis_w = get_distance(points_src_rotate[1], points_src_rotate[0]);
  580. int dis_h = get_distance(points_src_rotate[0], points_src_rotate[2]);
  581. int dis_ww = get_distance(points_dst[1], points_dst[0]);
  582. int dis_hw = get_distance(points_dst[0], points_dst[2]);
  583. double s_x = dis_w*1.0 / dis_ww*1.0;
  584. double s_y = dis_h*1.0 / dis_hw*1.0;
  585. int add_left = points_src_rotate[0].x - points_dst[0].x*s_x;
  586. int dis_w_right = (word_w - points_dst[1].x)*s_x;
  587. int dis_s_right = use_w - points_src_rotate[1].x;
  588. int add_right = dis_s_right - dis_w_right;
  589. int add_top = points_src_rotate[0].y - points_dst[0].y*s_y;
  590. int dis_w_bottom = (word_h - points_dst[1].y)*s_y;
  591. int dis_s_bottom = use_h - points_src_rotate[1].y;
  592. int add_bottom = dis_s_bottom - dis_w_bottom;
  593. IplImage* lp_after_warp = NULL;
  594. int xn_w = use_w - add_left - add_right;
  595. int xn_h = use_h - add_bottom - add_top;
  596. CvRect rc_box;//= cvRect(add_left,add_top,src0->width-add_left-add_right,src0->height-add_top-add_bottom);
  597. // 旋转矩形
  598. // 新的水平坐标点更新回 切割后的原图
  599. points_src_[0] = cvPoint2D32f(points_src_rotate[0].x - add_left, points_src_rotate[0].y - add_top);
  600. points_src_[1] = cvPoint2D32f(points_src_rotate[1].x - add_left, points_src_rotate[1].y - add_top);
  601. points_src_[2] = cvPoint2D32f(points_src_rotate[2].x - add_left, points_src_rotate[2].y - add_top);
  602. angle = 0.0;
  603. if (0 == dir) {
  604. rc_box = cvRect(add_left, add_top, src0->width - add_left - add_right, src0->height - add_top - add_bottom);
  605. lp_after_warp = cvCreateImage(cvSize(rc_box.width, rc_box.height), src0->depth, src0->nChannels);
  606. dst_img = cvCreateImage(cvSize(lp_after_warp->width, lp_after_warp->height), lp_after_warp->depth, lp_after_warp->nChannels);
  607. }
  608. else if (1 == dir){
  609. angle = -180;
  610. rc_box = cvRect(add_right, add_bottom, src0->width - add_left - add_right, src0->height - add_top - add_bottom);
  611. lp_after_warp = cvCreateImage(cvSize(rc_box.width, rc_box.height), src0->depth, src0->nChannels);
  612. dst_img = cvCreateImage(cvSize(lp_after_warp->width, lp_after_warp->height), lp_after_warp->depth, lp_after_warp->nChannels);
  613. }
  614. else if (2 == dir) {
  615. angle = -90;
  616. rc_box = cvRect(add_top, add_right, src0->width - add_top - add_bottom, src0->height - add_right - add_left);
  617. lp_after_warp = cvCreateImage(cvSize(rc_box.width, rc_box.height), src0->depth, src0->nChannels);
  618. dst_img = cvCreateImage(cvSize(lp_after_warp->height, lp_after_warp->width), lp_after_warp->depth, lp_after_warp->nChannels);
  619. }
  620. else if (3 == dir) {
  621. angle = -270;
  622. rc_box = cvRect(add_bottom, add_left, src0->width - add_bottom - add_top, src0->height - add_left - add_right);
  623. lp_after_warp = cvCreateImage(cvSize(rc_box.width, rc_box.height), src0->depth, src0->nChannels);
  624. dst_img = cvCreateImage(cvSize(lp_after_warp->height, lp_after_warp->width), lp_after_warp->depth, lp_after_warp->nChannels);
  625. }
  626. else
  627. return identify::result::IDF_FAILURE;
  628. if (angle < -1.0){
  629. for (int i = 0; i < 3; i++){
  630. points_src_[i] = get_new_point(points_src_[i], xn_w, xn_h, angle);
  631. }
  632. }
  633. cvSetImageROI(src0, rc_box);
  634. cvCopy(src0, lp_after_warp, NULL);
  635. #if _DEBUG
  636. cvSaveImage("D:\\show\\0.png", lp_after_warp);
  637. #endif
  638. cvResetImageROI(src0);
  639. //}
  640. use_w = lp_after_warp->width;
  641. use_h = lp_after_warp->height;
  642. if (dir > 1)
  643. swap(use_h, use_w);
  644. double d_x = use_w*1.0 / word_w;
  645. double d_y = use_h*1.0 / word_h;
  646. points_dst_[0] = cvPoint2D32f(points_dst_[0].x*d_x + 0.55, points_dst_[0].y*d_y + 0.55);
  647. points_dst_[1] = cvPoint2D32f(points_dst_[1].x*d_x + 0.55, points_dst_[1].y*d_y + 0.55);
  648. points_dst_[2] = cvPoint2D32f(points_dst_[2].x*d_x + 0.55, points_dst_[2].y*d_y + 0.55);
  649. #endif
  650. CvMat * warp_mat = cvCreateMat(2, 3, CV_32FC1);
  651. cvGetAffineTransform(points_src_, points_dst_, warp_mat);
  652. cvWarpAffine(lp_after_warp, dst_img, warp_mat, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvScalarAll(255));
  653. cvReleaseMat(&warp_mat);
  654. cvReleaseImage(&lp_after_warp);
  655. #if _DEBUG
  656. cvSaveImage("D:\\show\\1.png", src0);
  657. cvSaveImage("D:\\show\\2.png", dst_img);
  658. #endif
  659. return identify::result::IDF_SUCCESS;
  660. }
  661. int COnLineCardPageIdentifier::MyFindDingWeiDian(IplImage * src_gray_img, CvMemStorage* storage, schema_const_param &schema_param, vector<CvRect>& locate_point_list, int & _dir)
  662. {
  663. int range = m_pTemplate->dingweidian_range_top;
  664. //LOGFMTI("MyFindDingWeiDian 1 range=%d", range);
  665. CvRect roi[4] = {//上下左右 roi
  666. cvRect(0, 0, src_gray_img->width, min(range, src_gray_img->height)),
  667. cvRect(0, src_gray_img->height - min(range, src_gray_img->height) - 1, src_gray_img->width, min(range, src_gray_img->height)),
  668. cvRect(0, 0, min(range, src_gray_img->width), src_gray_img->height),
  669. cvRect(src_gray_img->width - min(range, src_gray_img->width) - 1, 0, min(range, src_gray_img->width), src_gray_img->height)
  670. };
  671. //LOGFMTI("MyFindDingWeiDian 2 range=%d", range);
  672. CvSeq * contour = NULL;
  673. for (int dir = 0; dir < 4; dir++)
  674. {
  675. if (dir < 2)myscale_shema_param0(m_default_schema_param, schema_param, src_gray_img->width / (double)m_default_schema_param.shijuanwidth);
  676. else myscale_shema_param0(m_default_schema_param, schema_param, src_gray_img->height / (double)m_default_schema_param.shijuanwidth);
  677. IplImage * binary_img = cvCreateImage(cvSize(roi[dir].width + 10, roi[dir].height + 10), IPL_DEPTH_8U, 1);
  678. IplImage * binary_img2 = cvCreateImage(cvSize(roi[dir].width + 10, roi[dir].height + 10), IPL_DEPTH_8U, 1);
  679. cvSet(binary_img, cvScalarAll(0));
  680. //LOGFMTI("MyFindDingWeiDian 3 x=%d y= %d,w = %d h = %d", roi[dir].x, roi[dir].y, roi[dir].width, roi[dir].height);
  681. cvSetImageROI(src_gray_img, roi[dir]);
  682. cvSetImageROI(binary_img, cvRect(5, 5, roi[dir].width, roi[dir].height));
  683. cvThreshold(src_gray_img, binary_img, 180, 255, CV_THRESH_BINARY_INV);
  684. cvResetImageROI(binary_img);
  685. int an = 2;
  686. IplConvKernel * element = cvCreateStructuringElementEx(an * 2 + 1, an * 2 + 1, an, an, CV_SHAPE_RECT, 0);//创建结构元素
  687. cvErode(binary_img, binary_img2, element, 1);//腐蚀图像
  688. cvDilate(binary_img2, binary_img2, element, 1);//膨胀图像
  689. cvSub(binary_img, binary_img2, binary_img2);
  690. cvDilate(binary_img, binary_img, element, 1);//膨胀图像
  691. cvErode(binary_img, binary_img, element, 1);//腐蚀图像
  692. cvSub(binary_img, binary_img2, binary_img);
  693. if (element)
  694. cvReleaseStructuringElement(&element);
  695. if (m_pTemplate->open_save_debug_img){
  696. char szImageName[1024] = { 0 };
  697. sprintf_s(szImageName, "%s\\image\\Debug\\find_dingweidian_top%d.jpg", g_appFilePathName, dir);
  698. cvSaveImage(szImageName, binary_img);
  699. }
  700. int contours = cvFindContours(binary_img, storage, &contour, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cvPoint(roi[dir].x - 5, roi[dir].y - 5));
  701. cvReleaseImage(&binary_img);
  702. cvReleaseImage(&binary_img2);
  703. int validCount = 0;
  704. vector<CvContour *> contourList;
  705. for (CvContour * c = (CvContour *)contour; c != 0; c = (CvContour *)c->h_next)
  706. {
  707. locate_point_list.clear();
  708. if (c->rect.width > schema_param.maxw[dir] * m_pTemplate->dingweidian_w_max_rate)continue;
  709. if (c->rect.height > schema_param.maxh[dir] * m_pTemplate->dingweidian_h_max_rate)continue;
  710. if (c->rect.width < schema_param.minw[dir] * m_pTemplate->dingweidian_w_min_rate)continue;
  711. if (c->rect.height < schema_param.minh[dir] * m_pTemplate->dingweidian_h_min_rate)continue;
  712. cvSetImageROI(src_gray_img, c->rect);
  713. int area = GetBlackArea(src_gray_img);
  714. if (area < c->rect.width*c->rect.height*0.75)continue;
  715. validCount++;
  716. contourList.push_back(c);
  717. }
  718. cvResetImageROI(src_gray_img);
  719. std::vector<CvRect> list;
  720. for (int i = 0; i < contourList.size(); i++)
  721. {
  722. CvRect rect = contourList[i]->rect;
  723. list.push_back(rect);
  724. }
  725. CvRect rect;
  726. float k = 0, b = 0;
  727. if (dir == 0 || dir == 1){
  728. std::sort(list.begin(), list.end(), sort_locate_point_by_x);
  729. }
  730. else {
  731. std::sort(list.begin(), list.end(), sort_locate_point_by_y);
  732. }
  733. if (list.size() > 1)
  734. {
  735. bool bV = false;
  736. locate_point_list.push_back(list[0]);
  737. if (list[list.size() - 1].x - list[0].x>-0.00001 && list[list.size() - 1].x - list[0].x<0.00001)
  738. {
  739. bV = true;
  740. }
  741. else{
  742. k = (list[list.size() - 1].y - list[0].y + 0.0) / (list[list.size() - 1].x - list[0].x);
  743. }
  744. b = list[0].y - k*list[0].x;
  745. for (int i = 1; i < list.size() - 1; i++)
  746. {
  747. if (dir == 0 || dir == 1){
  748. int y = k*list[i].x + b;
  749. if (fabs(y - list[i].y + 0.0) < list[i].height / 2)
  750. locate_point_list.push_back(list[i]);
  751. }
  752. else
  753. {
  754. int x = 0;
  755. if (bV){
  756. x = list[0].x;
  757. }
  758. else{
  759. x =(list[i].y - b) / k;
  760. }
  761. if (fabs(x - list[i].x + 0.0) < list[i].width / 2)
  762. locate_point_list.push_back(list[i]);
  763. }
  764. }
  765. locate_point_list.push_back(list[list.size() - 1]);
  766. }
  767. if (locate_point_list.size() == 3)
  768. {
  769. //LOGFMTI("MyFindDingWeiDian 4 range=%d", range);
  770. _dir = dir;
  771. if (MyFindBottomDingWeiDian(src_gray_img, storage, schema_param, locate_point_list, dir) == identify::result::IDF_FAILURE)
  772. return identify::result::IDF_FAILURE;
  773. //LOGFMTI("MyFindDingWeiDian 5 range=%d", range);
  774. return identify::result::IDF_SUCCESS;
  775. break;
  776. }
  777. }
  778. return identify::result::IDF_FAILURE;
  779. }
  780. //查找定位点
  781. int COnLineCardPageIdentifier::MyFindBottomDingWeiDian(IplImage * src_gray_img, CvMemStorage* storage, schema_const_param &schema_param, vector<CvRect>& locate_point_list, int & _dir)
  782. {
  783. int nRange = m_pTemplate->dingweidian_rang_buttom;
  784. CvRect roi[4] = {//上下左右 roi
  785. cvRect(0, 0, src_gray_img->width, min(nRange, src_gray_img->height)),
  786. cvRect(0, src_gray_img->height - min(nRange, src_gray_img->height) - 1, src_gray_img->width, min(nRange, src_gray_img->height)),
  787. cvRect(0, 0, min(nRange, src_gray_img->width), src_gray_img->height),
  788. cvRect(src_gray_img->width - min(nRange, src_gray_img->width) - 1, 0, min(nRange, src_gray_img->width), src_gray_img->height)
  789. };
  790. CvSeq * contour = NULL;
  791. int dir;
  792. _dir > 1 ? dir = 3 - _dir + 2 : dir = 1 - _dir;
  793. m_vecBottom.clear();
  794. //for (int dir=0;dir<4;dir++)
  795. {
  796. IplImage * binary_img = cvCreateImage(cvSize(roi[dir].width + 10, roi[dir].height + 10), IPL_DEPTH_8U, 1);
  797. IplImage * binary_img2 = cvCreateImage(cvSize(roi[dir].width + 10, roi[dir].height + 10), IPL_DEPTH_8U, 1);
  798. cvSet(binary_img, cvScalarAll(0));
  799. cvSetImageROI(src_gray_img, roi[dir]);
  800. cvSetImageROI(binary_img, cvRect(5, 5, roi[dir].width, roi[dir].height));
  801. cvThreshold(src_gray_img, binary_img, 180, 255, CV_THRESH_BINARY_INV);
  802. cvResetImageROI(binary_img);
  803. int an = 2;
  804. IplConvKernel * element = cvCreateStructuringElementEx(an * 2 + 1, an * 2 + 1, an, an, CV_SHAPE_RECT, 0);//创建结构元素
  805. cvErode(binary_img, binary_img2, element, 1);//腐蚀图像
  806. cvDilate(binary_img2, binary_img2, element, 1);//膨胀图像
  807. cvSub(binary_img, binary_img2, binary_img2);
  808. cvDilate(binary_img, binary_img, element, 1);//膨胀图像
  809. cvErode(binary_img, binary_img, element, 1);//腐蚀图像
  810. cvSub(binary_img, binary_img2, binary_img);
  811. if (m_pTemplate->open_save_debug_img){
  812. char szImageName[1024] = { 0 };
  813. sprintf_s(szImageName, "%s\\image\\Debug\\find_dingweidian_buttom%d.jpg", g_appFilePathName, dir);
  814. cvSaveImage(szImageName, binary_img);
  815. }
  816. int contours = cvFindContours(binary_img, storage, &contour, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cvPoint(roi[dir].x - 5, roi[dir].y - 5));
  817. if (element)
  818. cvReleaseStructuringElement(&element);
  819. cvReleaseImage(&binary_img);
  820. cvReleaseImage(&binary_img2);
  821. int validCount = 0;
  822. vector<CvContour *> contourList;
  823. for (CvContour * c = (CvContour *)contour; c != 0; c = (CvContour *)c->h_next)
  824. {
  825. if (c->rect.width > schema_param.maxw[dir] * m_pTemplate->dingweidian_w_max_rate)continue;
  826. if (c->rect.height > schema_param.maxh[dir] * m_pTemplate->dingweidian_h_max_rate)continue;
  827. if (c->rect.width < schema_param.minw[dir] * m_pTemplate->dingweidian_w_min_rate)continue;
  828. if (c->rect.height < schema_param.minh[dir] * m_pTemplate->dingweidian_h_min_rate)continue;
  829. cvSetImageROI(src_gray_img, c->rect);
  830. //cvSaveImage( "d://debug1.jpg", binary_img );
  831. int area = GetBlackArea(src_gray_img);
  832. if (area < c->rect.width*c->rect.height*0.75)continue;
  833. validCount++;
  834. contourList.push_back(c);
  835. }
  836. cvResetImageROI(src_gray_img);
  837. if (contourList.size() == 2){
  838. for (std::size_t i = 0; i < contourList.size(); i++){
  839. CvRect rect = contourList[i]->rect;
  840. m_vecBottom.push_back(rect);
  841. }
  842. if (m_vecBottom.size() > 1){
  843. std::sort(m_vecBottom.begin(), m_vecBottom.end(), sort_locate_point_by_x);
  844. if (_dir == 1)
  845. std::sort(m_vecBottom.begin(), m_vecBottom.end(), sort_locate_point_by_x);
  846. }
  847. return identify::result::IDF_SUCCESS;
  848. }
  849. else
  850. {
  851. // 大于要求数量
  852. if (contourList.size()>2)
  853. {
  854. //查找顶部定位点,宽高最大最小值
  855. int minw = locate_point_list[0].width;
  856. int maxw = locate_point_list[0].width;
  857. int minh = locate_point_list[0].height;
  858. int maxh = locate_point_list[0].height;
  859. for (int i = 1; i < locate_point_list.size(); i++)
  860. {
  861. //宽度计算
  862. if (locate_point_list[i].width > maxw)
  863. {
  864. maxw = locate_point_list[i].width;
  865. }
  866. else if (locate_point_list[i].width < minw)
  867. {
  868. minw = locate_point_list[i].width;
  869. }
  870. //高度计算
  871. if (locate_point_list[i].height > maxh)
  872. {
  873. maxh = locate_point_list[i].height;
  874. }
  875. else if (locate_point_list[i].height < minh)
  876. {
  877. minh = locate_point_list[i].height;
  878. }
  879. }
  880. minw = (schema_param.minw[dir] + minw) / 2;
  881. minh = (schema_param.minh[dir] + minh) / 2;
  882. maxw = (schema_param.maxw[dir] + maxw) / 2;
  883. maxh = (schema_param.maxh[dir] + maxh) / 2;
  884. // locate_point_list
  885. std::vector<CvRect> tempvecBottom;
  886. for (std::size_t i = 0; i < contourList.size(); i++){
  887. CvRect rect = contourList[i]->rect;
  888. if (rect.width >= minw && rect.width <= maxw && rect.height >= minh && rect.height <= maxh)
  889. {
  890. tempvecBottom.push_back(rect);
  891. }
  892. }
  893. if (tempvecBottom.size() == 2)
  894. {
  895. //成功找到数据
  896. for (std::size_t i = 0; i < tempvecBottom.size(); i++){
  897. m_vecBottom.push_back(tempvecBottom[i]);
  898. }
  899. if (m_vecBottom.size() > 1){
  900. std::sort(m_vecBottom.begin(), m_vecBottom.end(), sort_locate_point_by_x);
  901. if (_dir == 1)
  902. std::sort(m_vecBottom.begin(), m_vecBottom.end(), sort_locate_point_by_x);
  903. }
  904. return identify::result::IDF_SUCCESS;
  905. }
  906. else if (tempvecBottom.size() > 2)
  907. {
  908. //水平方向
  909. if (dir == 0 || dir == 1){
  910. std::sort(tempvecBottom.begin(), tempvecBottom.end(), sort_locate_point_by_x);
  911. //计算在识别区范围内
  912. float k = (float)(locate_point_list[locate_point_list.size() - 1].y - locate_point_list[0].y) / (locate_point_list[locate_point_list.size() - 1].x - locate_point_list[0].x);
  913. for (int i = 1; i < tempvecBottom.size() - 1; i++)
  914. {
  915. float y = tempvecBottom[0].y + k*(tempvecBottom[i].x - tempvecBottom[0].x);
  916. if ((tempvecBottom[i].y >(y - maxh)) && (tempvecBottom[i].y < (y + maxh)))
  917. return identify::result::IDF_FAILURE;
  918. }
  919. m_vecBottom.push_back(tempvecBottom[0]);
  920. m_vecBottom.push_back(tempvecBottom[tempvecBottom.size() - 1]);
  921. if (m_vecBottom.size() > 1){
  922. std::sort(m_vecBottom.begin(), m_vecBottom.end(), sort_locate_point_by_x);
  923. if (_dir == 1)
  924. std::sort(m_vecBottom.begin(), m_vecBottom.end(), sort_locate_point_by_x);
  925. }
  926. return identify::result::IDF_SUCCESS;
  927. }
  928. else {
  929. //水平方向垂直方向
  930. std::sort(tempvecBottom.begin(), tempvecBottom.end(), sort_locate_point_by_y);
  931. float k = (locate_point_list[locate_point_list.size() - 1].x - locate_point_list[0].x)/(float)(locate_point_list[locate_point_list.size() - 1].y - locate_point_list[0].y);
  932. for (int i = 1; i < tempvecBottom.size() - 1; i++)
  933. {
  934. float x = tempvecBottom[0].x + k*(tempvecBottom[i].y - tempvecBottom[0].y);
  935. if ((tempvecBottom[i].x >(x - maxw)) && (tempvecBottom[i].x < (x + maxw)))
  936. return identify::result::IDF_FAILURE;
  937. }
  938. m_vecBottom.push_back(tempvecBottom[0]);
  939. m_vecBottom.push_back(tempvecBottom[tempvecBottom.size() - 1]);
  940. if (m_vecBottom.size() > 1){
  941. std::sort(m_vecBottom.begin(), m_vecBottom.end(), sort_locate_point_by_x);
  942. if (_dir == 1)
  943. std::sort(m_vecBottom.begin(), m_vecBottom.end(), sort_locate_point_by_x);
  944. }
  945. return identify::result::IDF_SUCCESS;
  946. }
  947. }
  948. }
  949. return identify::result::IDF_FAILURE;
  950. }
  951. }
  952. }
  953. double COnLineCardPageIdentifier::CalcRectArea(IplImage* src, const std::vector<CvRect> & top_locate_point_list, const std::vector<CvRect> & bottom_locate_point_list)
  954. {
  955. int areaS = 0;
  956. int h = 0;
  957. int w = 0;
  958. std::vector<int> xVec;
  959. std::vector<int> yVec;
  960. for (int i = 0; i < top_locate_point_list.size(); i++)
  961. {
  962. xVec.push_back(top_locate_point_list[i].x);
  963. yVec.push_back(top_locate_point_list[i].y);
  964. }
  965. for (int i = 0; i < bottom_locate_point_list.size(); i++)
  966. {
  967. xVec.push_back(bottom_locate_point_list[i].x);
  968. yVec.push_back(bottom_locate_point_list[i].y);
  969. }
  970. std::sort(xVec.begin(), xVec.end());
  971. std::sort(yVec.begin(), yVec.end());
  972. areaS = (xVec[yVec.size() - 1] - xVec[0]) *(yVec[yVec.size() - 1] - yVec[0]);
  973. return (double)areaS / (double)(src->width*src->height);
  974. }
  975. int COnLineCardPageIdentifier::OnLineCardJZ(IplImage* src, IplImage* &dst_img, int nPageIndex, int dir, std::vector<CvRect>&main_locate_point, int &wordloctlt)
  976. {
  977. int ret = identify::result::IDF_FAILURE;
  978. std::vector<CvRect> vec_locations_word; vec_locations_word.clear();
  979. double tt[4] = { 0.0, 0.0, 0.0, 0.0 };
  980. if (!m_pTemplate->pages.empty()){
  981. PageTemplate&page = m_pTemplate->pages[nPageIndex];
  982. std::vector<Location>& lcs = page.location;
  983. for (std::size_t j = 0; j < lcs.size(); j++){
  984. CvRect rc_tmp;
  985. rc_tmp.x = lcs[j].pos.x;
  986. rc_tmp.y = lcs[j].pos.y;
  987. rc_tmp.width = lcs[j].pos.w;
  988. rc_tmp.height = lcs[j].pos.h;
  989. vec_locations_word.push_back(rc_tmp);
  990. }
  991. std::sort(vec_locations_word.begin(), vec_locations_word.end(), sort_locate_point_by_y);
  992. wordloctlt = vec_locations_word[vec_locations_word.size() - 1].y - vec_locations_word[0].y;
  993. double word_w = page.w;
  994. double word_h = page.h;
  995. tt[2] = word_w;
  996. tt[3] = word_h;
  997. // resize point
  998. int mb_w = src->width;
  999. int mb_h = src->height;
  1000. if (2 == dir || 3 == dir) //
  1001. swap(mb_h, mb_w);
  1002. float rio_w = mb_w*1.0 / word_w*1.0;
  1003. float rio_h = mb_h*1.0 / word_h*1.0;
  1004. tt[0] = rio_w;
  1005. tt[1] = rio_h;
  1006. for (std::size_t i = 0; i < vec_locations_word.size(); i++){
  1007. vec_locations_word[i].x = vec_locations_word[i].x*rio_w + 0.55;
  1008. vec_locations_word[i].y = vec_locations_word[i].y*rio_h + 0.55;
  1009. vec_locations_word[i].width = vec_locations_word[i].width*rio_w + 0.55;
  1010. vec_locations_word[i].height = vec_locations_word[i].height*rio_h + 0.55;
  1011. }
  1012. }
  1013. if (2 == m_vecBottom.size() && vec_locations_word.size()>3){
  1014. try{
  1015. // 三点校正
  1016. ret = JiaoZheng_20200418_first(src, dst_img, main_locate_point, m_vecBottom, vec_locations_word, dir);
  1017. }
  1018. catch (cv::Exception &e)
  1019. {
  1020. return identify::result::IDF_FAILURE;
  1021. }
  1022. }
  1023. return ret;
  1024. }
  1025. void COnLineCardPageIdentifier::InitScoreArea(SchemaQuestionScore&sqs, const ScoreBox&box, CvPoint offset, double w_scale, double h_scale)
  1026. {
  1027. // 打分框类型
  1028. sqs.scoreBox.type = box.type;
  1029. // 填空题打分类型
  1030. sqs.scoreBox.vctScore = box.vctScore;
  1031. // 上限
  1032. sqs.scoreBox.limit = box.limit;
  1033. // 最后一个格子是否为小数(0.5分)
  1034. sqs.scoreBox.bPoint = box.bPoint;
  1035. // 位置
  1036. sqs.scoreBox.pos.x = offset.x + box.pos.x * w_scale;
  1037. sqs.scoreBox.pos.y = offset.y + box.pos.y * h_scale;
  1038. sqs.scoreBox.pos.w = box.pos.w *w_scale;
  1039. sqs.scoreBox.pos.h = box.pos.h *h_scale;
  1040. }
  1041. int COnLineCardPageIdentifier::GetQrCode(IplImage* dst_gray_img, schema_const_param &schema_param, vector<CvRect> &main_locate_point, vector<SchemaCode> &codev, string& paper_id, string& student_code, int code_type)
  1042. {
  1043. std::string result;
  1044. CvRect myRect = cvRect( main_locate_point[0].x + schema_param.paper_bar_offsetx1,
  1045. main_locate_point[0].y + schema_param.paper_bar_offsety1,
  1046. schema_param.paper_bar_width1,
  1047. schema_param.paper_bar_height1);
  1048. IplImage* mydst_gray_img = NULL;
  1049. xuanzhuan(dst_gray_img, mydst_gray_img, myRect);
  1050. m_pTemplate->open_save_debug_img = 1;
  1051. if (m_pTemplate->open_save_debug_img)
  1052. {
  1053. string tempfile = g_appFilePathName + "\\image\\Debug\\GetQrCode.JPG";
  1054. cv::imwrite(tempfile.c_str(), cvarrToMat(mydst_gray_img));
  1055. }
  1056. cv::Mat matDstGray = cvarrToMat(mydst_gray_img);
  1057. int ret = 0;
  1058. try{
  1059. // ret = GetQR(matDstGray, result);
  1060. char szRes[1024];
  1061. ret = api_parse_barcode_qrcode(matDstGray, code_type, szRes, 1024);
  1062. result = szRes;
  1063. }
  1064. catch (cv::Exception&e){
  1065. const char* what = e.what();
  1066. int n = 0;
  1067. ++n;
  1068. }
  1069. //CParseQRInfo test;
  1070. //char result[512] = { 0 };
  1071. //bool bRet = test.parseQRInfo(matDstGray, result, sizeof(result)/sizeof(char));
  1072. //if (/*ret == identify::result::IDF_SUCCESS*/bRet){
  1073. if (ret == identify::result::IDF_SUCCESS){
  1074. SchemaCode qrcode1;
  1075. qrcode1.centerx = (main_locate_point[0].x + schema_param.paper_bar_offsetx1) + schema_param.paper_bar_width1 / 2.0;
  1076. qrcode1.centery = (main_locate_point[0].y + schema_param.paper_bar_offsety1) + schema_param.paper_bar_height1 / 2.0;
  1077. qrcode1.width = schema_param.paper_bar_width1;
  1078. qrcode1.height = schema_param.paper_bar_height1;
  1079. qrcode1.index = obj_index++;
  1080. qrcode1.nQrOrBar = 1;
  1081. qrcode1.isXuanZhuan = false;
  1082. student_code = result;
  1083. qrcode1.strContent = result;
  1084. codev.push_back(qrcode1);
  1085. }
  1086. if (mydst_gray_img != NULL)cvReleaseImage(&mydst_gray_img);
  1087. return identify::result::IDF_SUCCESS;
  1088. }
  1089. void COnLineCardPageIdentifier::CalcPos(const Pos&pos, const CvPoint& offset, double w_scale, double h_scale, int &center_x, int &center_y, int &w, int &h)
  1090. {
  1091. w = static_cast<int>(pos.w*w_scale);
  1092. h = static_cast<int>(pos.h*h_scale);
  1093. center_x = static_cast<int>(offset.x + pos.x*w_scale + pos.w*w_scale / 2);
  1094. center_y = static_cast<int>(offset.y + pos.y*h_scale + pos.h*h_scale / 2);
  1095. }
  1096. void COnLineCardPageIdentifier::SetPageDefault(SchemaPage& page)
  1097. {
  1098. page.codeCount = 0;
  1099. page.cutAreaCount = 0;
  1100. page.group_spacer = ';';
  1101. page.groupCount = 0;
  1102. page.stuItemCount = 0;
  1103. page.stuGroupsCount = 0;
  1104. page.hei_du_ling_min_du = 4;
  1105. page.height = 0;
  1106. page.index = 0;
  1107. page.itemCount = 0;
  1108. page.locateAreaCount = 0;
  1109. page.locateCrossCount = 0;
  1110. page.locatePointCount = 0;
  1111. page.option_spacer = ',';
  1112. page.question_score_count = 0;
  1113. page.unselect_char = '*';
  1114. page.user_float_heidu = 4;
  1115. page.width = 0;
  1116. page.worthwhileBlk = 4;
  1117. }
  1118. void COnLineCardPageIdentifier::SetTemplate(OnLineCard::PaperTemplate*pT)
  1119. {
  1120. m_pTemplate = pT;
  1121. int dingweidianH;
  1122. int dingweidianW;
  1123. if (m_pTemplate->pages[1].location.size() >= 5){
  1124. int m = 0;
  1125. dingweidianH = m_pTemplate->pages[1].location[m].pos.h;
  1126. dingweidianW = m_pTemplate->pages[1].location[m].pos.w;
  1127. std::vector<Location> vecLocation = m_pTemplate->pages[1].location;
  1128. std::sort(vecLocation.begin(), vecLocation.end(), [=](Location l1, Location l2){ return l1.pos.x < l2.pos.x; });
  1129. m_default_schema_param.main_locate_point_distance = vecLocation.at(vecLocation.size() - 1).pos.x - vecLocation.begin()->pos.x;
  1130. m_default_schema_param.shijuanwidth = m_pTemplate->pages[1].w;
  1131. for (int i = 0; i < 4; i++)
  1132. {
  1133. if (i < 2)
  1134. {
  1135. m_default_schema_param.minw[i] = dingweidianW*0.75;
  1136. m_default_schema_param.maxw[i] = dingweidianW*1.25;
  1137. m_default_schema_param.minh[i] = dingweidianH*0.75;
  1138. m_default_schema_param.maxh[i] = dingweidianH*1.25;
  1139. }
  1140. else
  1141. {
  1142. m_default_schema_param.minw[i] = dingweidianH*0.75;
  1143. m_default_schema_param.maxw[i] = dingweidianH*1.25;
  1144. m_default_schema_param.minh[i] = dingweidianW*0.75;
  1145. m_default_schema_param.maxh[i] = dingweidianW*1.25;
  1146. }
  1147. }
  1148. }
  1149. }
  1150. #ifdef _draw_debug
  1151. void drawDebug(IplImage* dst_img, PageTemplate*page)
  1152. {
  1153. if (!dst_img)return;
  1154. double w_rate = dst_img->width*1.0 / page->w;
  1155. double h_rate = dst_img->height*1.0 / page->h;
  1156. auto pDrawFunc = [&](const OnLineCard::Pos&pos, CvScalar clr,bool flag){
  1157. cvDrawRect(dst_img,
  1158. cvPoint(((flag ? 0 : page->location[0].pos.x) + pos.x)*w_rate, ((flag ? 0 : page->location[0].pos.y) + pos.y)*h_rate),
  1159. cvPoint(((flag ? 0 : page->location[0].pos.x) + pos.x + pos.w)*w_rate, ((flag ? 0 : page->location[0].pos.y) + pos.y + pos.h)*h_rate),
  1160. clr);
  1161. };
  1162. // 绘制定位点
  1163. for (auto it : page->location){
  1164. pDrawFunc(it.pos, CvScalar(0, 255, 0),true);
  1165. }
  1166. if (page->pageNo==1){ // 首页
  1167. for (auto it : page->studentcode_fill){
  1168. for (auto it1:it){
  1169. pDrawFunc(it1.pos, CvScalar(0, 255, 0), false);
  1170. }
  1171. }
  1172. pDrawFunc(page->absent, CvScalar(0, 255, 0), false);
  1173. pDrawFunc(page->QrCode, CvScalar(0, 255, 0), false);
  1174. }
  1175. for (auto it: page->vctQuestions)
  1176. {
  1177. for (auto opt: it.opt){
  1178. pDrawFunc(opt.pos, CvScalar(0, 255, 0), false);
  1179. }
  1180. pDrawFunc(it.scoreBox.pos, CvScalar(0, 255, 0), false);
  1181. pDrawFunc(it.cut.pos, CvScalar(255, 255, 0), false);
  1182. }
  1183. std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> tp = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
  1184. auto tmp = std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
  1185. std::time_t timestamp = tmp.count();
  1186. std::string filetemppath = g_appFilePathName + "\\image1\\";
  1187. CreateDirectoryA(filetemppath.c_str(), NULL);
  1188. std::string path = g_appFilePathName + std::string("\\image1\\") + std::to_string(timestamp) + ".jpg";
  1189. cvSaveImage(path.c_str(), dst_img);
  1190. }
  1191. #endif
  1192. //构建试卷的识别区域
  1193. int COnLineCardPageIdentifier::createSchema(const IplImage* src, IplImage* *dst, SchemaPage* *pageSchema, const char * result_path, bool flag, std::string qr, bool bUseQr)
  1194. {
  1195. ////LOGI("createSchema 1");
  1196. if (!m_pTemplate /*|| m_pTemplate->pages.size() < 2 */|| m_pTemplate->pages[1].location.size() < 5){
  1197. return identify::result::IDF_FAILURE;
  1198. }
  1199. int wordloctlt = 0;
  1200. int schoolCardStatus = m_pTemplate->schoolCardStatus;
  1201. obj_index = 0;
  1202. //#ifdef _draw_debug
  1203. // IplImage*src_debug = cvCloneImage(src);
  1204. //#endif
  1205. ////LOGI("createSchema 1.3");
  1206. CvRect roi_old = cvGetImageROI(src);
  1207. IplImage * src0 = (IplImage *)src;
  1208. int ret;
  1209. int mode_type = 1115;
  1210. vector<SchemaGroup> groupv;
  1211. vector<SchemaItem> itemv;
  1212. vector<SchemaQuestionScore> scorev;
  1213. vector<SchemaCode> codev;
  1214. vector<SchemaCutArea> cutareav;
  1215. vector<SchemaLocatePoint> questionLocatePoints;
  1216. vector<KEGUANTI_QUESTION_LOCATEPOINT_INDEX> keguanti_question_locatepoint_indexs;
  1217. vector<SchemaGroup> stuGroupv;
  1218. vector<SchemaItem> stuItemv;
  1219. vector<KEGUANTI_QUESTION_LOCATEPOINT_INDEX> stuIndex;
  1220. vector<KEGUANTI_QUESTION_LOCATEPOINT_INDEX> quekaoIndex;
  1221. int qrFlag = 0;
  1222. ////LOGI("createSchema 1.31");
  1223. CvMemStorage* storage = cvCreateMemStorage(0);
  1224. IplImage * src_gray_img;
  1225. int question_count = 0;
  1226. int itemcount = 0;
  1227. ////LOGI("createSchema 1.4");
  1228. cvResetImageROI((IplImage*)src0);
  1229. ////LOGI("createSchema 1.41");
  1230. src_gray_img = cvCreateImage(cvGetSize(src0), IPL_DEPTH_8U, 1);
  1231. ////LOGI("createSchema 1.42");
  1232. #ifdef _DEBUG
  1233. m_pTemplate->open_save_debug_img = true;
  1234. cvSaveImage("d:\\image\\src0.png", src0);
  1235. cvSaveImage("d:\\image\\src_gray_img.png", src_gray_img);
  1236. #endif
  1237. cvCvtColor(src0, src_gray_img, CV_BGR2GRAY);
  1238. ////LOGI("createSchema 1.43");
  1239. ////LOGI("createSchema 1.5");
  1240. schema_const_param schema_param;
  1241. std::vector<CvRect> main_locate_point;
  1242. CvPoint offset_pt;
  1243. int dir;//上下左右
  1244. //1.查找定位点
  1245. // printf("线程:%s 第一次查找定位点\n", std::to_string(GetCurrentThreadId()).c_str());
  1246. ret = MyFindDingWeiDian(src_gray_img, storage, schema_param, main_locate_point, dir);
  1247. if (ret != identify::result::IDF_SUCCESS){
  1248. cv::Size sz;
  1249. std::vector<cv::Rect> vec_locations_word; vec_locations_word.clear();
  1250. if (!m_pTemplate->pages.empty()){
  1251. PageTemplate&page = m_pTemplate->pages[1];
  1252. sz = cv::Size(page.w, page.h);
  1253. std::vector<Location>& lcs = page.location;
  1254. for (std::size_t j = 0; j < lcs.size(); j++){
  1255. cv::Rect rc_tmp;
  1256. rc_tmp.x = lcs[j].pos.x;
  1257. rc_tmp.y = lcs[j].pos.y;
  1258. rc_tmp.width = lcs[j].pos.w;
  1259. rc_tmp.height = lcs[j].pos.h;
  1260. vec_locations_word.push_back(rc_tmp);
  1261. }
  1262. }
  1263. std::vector<cv::Rect> vec_tops; // 接受找到的上面三个定位点 下标访问
  1264. std::vector<cv::Rect> vec_bottoms; // 接受找到的下面的两个定位点 下标访问
  1265. std::vector<int> vec_len;
  1266. vec_tops.resize(100);
  1267. vec_bottoms.resize(100);
  1268. vec_len.push_back(-1);
  1269. vec_len.push_back(-1);
  1270. #ifdef _DEBUG
  1271. cv::imwrite("D:\\src_gray_img.png", cv::cvarrToMat(src_gray_img));
  1272. #endif
  1273. int nRet = api_location_anchor_points(cv::cvarrToMat(src_gray_img), vec_locations_word, sz, vec_tops, vec_bottoms, vec_len, dir, 3, 1);
  1274. if (nRet == 0 && vec_len.size() == 2 && vec_len[0] == 3 && vec_len[1] == 2){
  1275. main_locate_point.clear();
  1276. m_vecBottom.clear();
  1277. for (std::size_t i = 0; i < vec_tops.size() && i < vec_len[0]; ++i){
  1278. main_locate_point.push_back(vec_tops[i]);
  1279. }
  1280. for (std::size_t i = 0; i < vec_bottoms.size() && i < vec_len[1]; ++i){
  1281. m_vecBottom.push_back(vec_bottoms[i]);
  1282. }
  1283. }
  1284. else{
  1285. cvReleaseMemStorage(&storage);
  1286. cvReleaseImage(&src_gray_img);
  1287. cvSetImageROI(src0, roi_old);
  1288. return identify::result::IDF_TEMPLATE_NOTFOUND_ENOUGH_LOCATEPOINT;
  1289. }
  1290. }
  1291. if (m_nOnlineScanType == 0)
  1292. {
  1293. // 魔法词汇宝
  1294. if (CalcRectArea(src0, main_locate_point, m_vecBottom) < POSITION_JUGDMENT_THRESHOLD)
  1295. {
  1296. cvReleaseMemStorage(&storage);
  1297. cvReleaseImage(&src_gray_img);
  1298. cvSetImageROI(src0, roi_old);
  1299. return identify::result::IDF_TEMPLATE_NOTFOUND_ENOUGH_LOCATEPOINT;
  1300. }
  1301. }
  1302. IplImage * dst_img = NULL;
  1303. //2.矫正图像
  1304. ret = OnLineCardJZ(src0, dst_img, 1, dir, main_locate_point, wordloctlt);
  1305. if (ret != identify::result::IDF_SUCCESS){
  1306. cvReleaseMemStorage(&storage);
  1307. cvReleaseImage(&src_gray_img);
  1308. cvSetImageROI(src0, roi_old);
  1309. if (dst_img)cvReleaseImage(&dst_img);
  1310. return identify::result::IDF_TEMPLATE_NOTFOUND_ENOUGH_LOCATEPOINT;
  1311. }
  1312. IplImage* dst_gray_img = cvCreateImage(cvGetSize(dst_img), IPL_DEPTH_8U, 1);
  1313. cvCvtColor(dst_img, dst_gray_img, CV_BGR2GRAY);
  1314. int locate_point_count = main_locate_point.size();
  1315. main_locate_point.clear();
  1316. ret = MyFindDingWeiDian(dst_gray_img, storage, schema_param, main_locate_point, dir);
  1317. std::sort(main_locate_point.begin(), main_locate_point.end(), sort_locate_point_by_x);
  1318. if (ret != identify::result::IDF_SUCCESS || main_locate_point.size() != locate_point_count){
  1319. cv::Size sz;
  1320. std::vector<cv::Rect> vec_locations_word; vec_locations_word.clear();
  1321. if (!m_pTemplate->pages.empty()){
  1322. PageTemplate&page = m_pTemplate->pages[1];
  1323. sz = cv::Size(page.w, page.h);
  1324. std::vector<Location>& lcs = page.location;
  1325. for (std::size_t j = 0; j < lcs.size(); j++){
  1326. cv::Rect rc_tmp;
  1327. rc_tmp.x = lcs[j].pos.x;
  1328. rc_tmp.y = lcs[j].pos.y;
  1329. rc_tmp.width = lcs[j].pos.w;
  1330. rc_tmp.height = lcs[j].pos.h;
  1331. vec_locations_word.push_back(rc_tmp);
  1332. }
  1333. }
  1334. std::vector<cv::Rect> vec_tops; // 接受找到的上面三个定位点 下标访问
  1335. std::vector<cv::Rect> vec_bottoms; // 接受找到的下面的两个定位点 下标访问
  1336. std::vector<int> vec_len;
  1337. vec_tops.resize(100);
  1338. vec_bottoms.resize(100);
  1339. vec_len.push_back(-1);
  1340. vec_len.push_back(-1);
  1341. int nRet = api_location_anchor_points(cv::cvarrToMat(dst_gray_img), vec_locations_word, sz, vec_tops, vec_bottoms, vec_len, dir, 3, 1);
  1342. if (nRet == 0 && vec_len.size() == 2 && vec_len[0] == 3 && vec_len[1] == 2){
  1343. main_locate_point.clear();
  1344. m_vecBottom.clear();
  1345. for (std::size_t i = 0; i < vec_tops.size() && i < vec_len[0]; ++i){
  1346. main_locate_point.push_back(vec_tops[i]);
  1347. }
  1348. for (std::size_t i = 0; i < vec_bottoms.size() && i < vec_len[1]; ++i){
  1349. m_vecBottom.push_back(vec_bottoms[i]);
  1350. }
  1351. }
  1352. else{
  1353. cvReleaseMemStorage(&storage);
  1354. cvReleaseImage(&src_gray_img);
  1355. cvReleaseImage(&dst_gray_img);
  1356. cvSetImageROI(src0, roi_old);
  1357. if (dst_img)cvReleaseImage(&dst_img);
  1358. return identify::result::IDF_TEMPLATE_NOTFOUND_ENOUGH_LOCATEPOINT;
  1359. }
  1360. }
  1361. //3.确定模板和识别图片的比例关系
  1362. double fffx = (main_locate_point[main_locate_point.size() - 1].x - main_locate_point[0].x)*(main_locate_point[main_locate_point.size() - 1].x - main_locate_point[0].x);
  1363. double fffy = (main_locate_point[main_locate_point.size() - 1].y - main_locate_point[0].y)*(main_locate_point[main_locate_point.size() - 1].y - main_locate_point[0].y);
  1364. double w_scale = (sqrt(fffx + fffy)) / m_default_schema_param.main_locate_point_distance;
  1365. double Hfffx = (m_vecBottom[0].x - main_locate_point[0].x)*(m_vecBottom[0].x - main_locate_point[0].x);
  1366. double Hfffy = (m_vecBottom[0].y - main_locate_point[0].y)*(m_vecBottom[0].y - main_locate_point[0].y);
  1367. double h_scale = (sqrt(Hfffx + Hfffy)) / wordloctlt;
  1368. {
  1369. //保存
  1370. SchemaLocatePoint leftp;
  1371. leftp.centerx = main_locate_point[0].x + main_locate_point[0].width / 2.0;
  1372. leftp.centery = main_locate_point[0].y + main_locate_point[0].height / 2.0;
  1373. leftp.width = main_locate_point[0].width;
  1374. leftp.height = main_locate_point[0].height;
  1375. questionLocatePoints.push_back(leftp);
  1376. SchemaLocatePoint rightp;
  1377. rightp.centerx = main_locate_point[2].x + main_locate_point[2].width / 2.0;
  1378. rightp.centery = main_locate_point[2].y + main_locate_point[2].height / 2.0;
  1379. rightp.width = main_locate_point[2].width;
  1380. rightp.height = main_locate_point[2].height;
  1381. questionLocatePoints.push_back(rightp);
  1382. leftp.centerx = m_vecBottom[0].x + m_vecBottom[0].width / 2.0;
  1383. leftp.centery = m_vecBottom[0].y + m_vecBottom[0].height / 2.0;
  1384. leftp.width = m_vecBottom[0].width;
  1385. leftp.height = m_vecBottom[0].height;
  1386. questionLocatePoints.push_back(leftp);
  1387. rightp.centerx = m_vecBottom[1].x + m_vecBottom[1].width / 2.0;
  1388. rightp.centery = m_vecBottom[1].y + m_vecBottom[1].height / 2.0;
  1389. rightp.width = m_vecBottom[1].width;
  1390. rightp.height = m_vecBottom[1].height;
  1391. questionLocatePoints.push_back(rightp);
  1392. }
  1393. std::string exam_id_by_qr_code;
  1394. bool is_same_exam_id = true;
  1395. int page_index = 1;
  1396. string paper_id = "";
  1397. string student_code = "";
  1398. bool is_stu_id = false;
  1399. offset_pt.x = main_locate_point[0].x;
  1400. offset_pt.y = main_locate_point[0].y;
  1401. bool front_page = false;
  1402. //判断前后页
  1403. if ((main_locate_point[1].x - main_locate_point[0].x) < (main_locate_point[2].x - main_locate_point[1].x)){//正面
  1404. front_page = true;
  1405. }
  1406. else{
  1407. front_page = false;
  1408. }
  1409. PageTemplate&page = m_pTemplate->pages[front_page ? 1 : 2];
  1410. //#ifdef _draw_debug
  1411. // drawDebug(src_debug, &page);
  1412. // cvReleaseImage(&src_debug);
  1413. //#endif
  1414. #ifdef _draw_debug
  1415. IplImage*src_debug = cvCloneImage(dst_img);
  1416. #endif
  1417. ////LOGI("createSchema 5");
  1418. // 正面
  1419. if (front_page){
  1420. SchemaCode code_tmp;
  1421. std::vector<std::string> split_qr;
  1422. split(qr, (std::string)",", &split_qr);
  1423. if (split_qr.size() > 0){
  1424. if (split_qr.size() > 0)
  1425. paper_id = split_qr[0];
  1426. if (bUseQr){
  1427. if (split_qr.size() > 2){
  1428. std::vector<std::string> _vct;
  1429. split(split_qr[2], std::string("@"), &_vct);
  1430. if (_vct.size() > 1){
  1431. student_code = _vct[2];
  1432. is_stu_id = !student_code.empty();
  1433. }
  1434. }
  1435. }
  1436. }
  1437. if (bUseQr&&!student_code.empty())
  1438. {
  1439. SchemaCode code;
  1440. code.index = obj_index++;
  1441. code.nQrOrBar = 1;
  1442. code.strContent = paper_id + "_" + student_code + "_3_1";
  1443. codev.push_back(code);
  1444. }
  1445. else{
  1446. // 二维码
  1447. double x = page.QrCode.x*w_scale - 20;
  1448. double y = page.QrCode.y*h_scale - 20;
  1449. schema_param.paper_bar_width1 = page.QrCode.w*w_scale + 40;
  1450. if (schema_param.paper_bar_width1 + x >= dst_gray_img->width)
  1451. schema_param.paper_bar_width1 = dst_gray_img->width - x - 2;
  1452. schema_param.paper_bar_height1 = page.QrCode.h*h_scale + 40;
  1453. schema_param.paper_bar_offsetx1 = x;
  1454. schema_param.paper_bar_offsety1 = y;
  1455. if (m_pTemplate->useQrCode){
  1456. std::size_t nOld = codev.size();
  1457. ret = GetQrCode(dst_gray_img, schema_param, main_locate_point, codev, paper_id, student_code, CODE_QR);
  1458. if (student_code != "")
  1459. qrFlag = 1;
  1460. else
  1461. qrFlag = -1;
  1462. if (ret != identify::result::IDF_SUCCESS){
  1463. cvReleaseMemStorage(&storage);
  1464. cvReleaseImage(&src_gray_img);
  1465. cvReleaseImage(&dst_img);
  1466. cvReleaseImage(&dst_gray_img);
  1467. return identify::result::IDF_TEMPLATE_QRCODE_ILLEGAL;
  1468. }
  1469. if (nOld < codev.size()){
  1470. vector<std::string> splits;
  1471. split(student_code, (std::string)"@", &splits);
  1472. if (splits.size() == 1){
  1473. paper_id = splits[0];
  1474. codev[codev.size() - 1].strContent = paper_id + "_6582234412574771625_3_1_12_1_1_1";
  1475. student_code = "";
  1476. }
  1477. else if (splits.size() >= 2){
  1478. student_code = splits[0];
  1479. paper_id = splits[1];
  1480. codev[codev.size() - 1].strContent = paper_id + "_" + student_code + "_3_1";
  1481. }
  1482. if (splits.size()> 0)
  1483. {
  1484. std::lock_guard<std::mutex> _lck(g_mtx_examid);
  1485. if (g_examid_by_qr_code.load() == 0){
  1486. g_examid_by_qr_code.store(1);
  1487. exam_id_by_qr_code = paper_id;
  1488. std::string str_cfg_path = GetExePath() + "\\paperinfo.ini";
  1489. char cfg_exam_id[128] = { 0 };
  1490. //paperinfo/exam_id
  1491. GetPrivateProfileStringA("paperinfo", "exam_id", "", cfg_exam_id, 128, str_cfg_path.c_str());
  1492. if (exam_id_by_qr_code != cfg_exam_id && m_nOnlineScanType != 0){
  1493. is_same_exam_id = false;
  1494. }
  1495. }
  1496. }
  1497. if (student_code.empty()){
  1498. if (!codev.empty())
  1499. code_tmp = codev[0];
  1500. codev.clear();
  1501. }
  1502. }
  1503. is_stu_id = !student_code.empty();
  1504. }
  1505. else{
  1506. std::lock_guard<std::mutex> _lck(g_mtx_examid);
  1507. if (g_examid_by_qr_code.load() == 0){
  1508. std::string paper_id, student_code;
  1509. std::vector<SchemaCode> vct_tmp_codev;
  1510. ret = GetQrCode(dst_gray_img, schema_param, main_locate_point, vct_tmp_codev, student_code, student_code, CODE_QR);
  1511. if (!vct_tmp_codev.empty()){
  1512. vector<std::string> splits;
  1513. split(student_code, (std::string)"@", &splits);
  1514. if (splits.size() == 1){
  1515. paper_id = splits[0];
  1516. student_code = "";
  1517. }
  1518. else if (splits.size() >= 2){
  1519. student_code = splits[0];
  1520. paper_id = splits[1];
  1521. }
  1522. g_examid_by_qr_code.store(1);
  1523. exam_id_by_qr_code = paper_id;
  1524. std::string str_cfg_path = GetExePath() + "\\paperinfo.ini";
  1525. char cfg_exam_id[128] = { 0 };
  1526. //paperinfo/exam_id
  1527. GetPrivateProfileStringA("paperinfo", "exam_id", "", cfg_exam_id, 128, str_cfg_path.c_str());
  1528. if (exam_id_by_qr_code != cfg_exam_id && m_nOnlineScanType != 0){
  1529. is_same_exam_id = false;
  1530. }
  1531. }
  1532. }
  1533. }
  1534. // 二维码中含有学生信息 不需要识别条形码和填涂考号
  1535. if (!m_pTemplate->useQrCode)
  1536. {
  1537. //条形码
  1538. schema_param.paper_bar_width1 = page.studentcode_bar.w*w_scale;
  1539. schema_param.paper_bar_height1 = page.studentcode_bar.h*h_scale;
  1540. schema_param.paper_bar_offsetx1 = page.studentcode_bar.x*w_scale;
  1541. schema_param.paper_bar_offsety1 = page.studentcode_bar.y*h_scale;
  1542. if (schema_param.paper_bar_width1 != 0 && schema_param.paper_bar_height1 != 0){
  1543. auto oldSize = codev.size();
  1544. ret = GetQrCode(dst_gray_img, schema_param, main_locate_point, codev, paper_id, student_code, CODE_BAR);
  1545. if (ret != identify::result::IDF_SUCCESS){
  1546. cvReleaseMemStorage(&storage);
  1547. cvReleaseImage(&src_gray_img);
  1548. cvReleaseImage(&dst_img);
  1549. cvReleaseImage(&dst_gray_img);
  1550. return identify::result::IDF_TEMPLATE_QRCODE_ILLEGAL;;
  1551. }
  1552. if (oldSize < codev.size()){
  1553. codev[codev.size() - 1].strContent = paper_id + "_" + student_code + "_3_1_12_1_1_1";
  1554. }
  1555. }
  1556. //填涂考号
  1557. if (student_code.empty())
  1558. {
  1559. int q_item_count = 10;
  1560. int itemcount = 0;
  1561. int question_count = 0;
  1562. int x, y, w, h;
  1563. for (std::size_t j = 0; j < page.studentcode_fill.size(); j++)
  1564. {
  1565. SchemaGroup group;
  1566. group.question_code = "";
  1567. group.index = question_count++;
  1568. group.question_index = question_count;
  1569. group.itemCount = q_item_count;
  1570. group.itemIndex.clear();
  1571. group.omr_out_type = OMR_OUT_TYPE::OMR_OUT_TYPE_SINGLE_NONSTRICT;
  1572. for (std::size_t m = 0; m < page.studentcode_fill[j].size(); m++)
  1573. {
  1574. group.itemIndex.push_back(itemcount + m);
  1575. SchemaItem item;
  1576. CalcPos(page.studentcode_fill[j][m].pos, offset_pt, w_scale, h_scale, item.centerx, item.centery, item.width, item.height);
  1577. std::string&optName = page.studentcode_fill[j][m].optName;
  1578. if (!optName.empty())
  1579. item.OutChar = std::stoi(optName) + '0';
  1580. item.keguanti_question_locate_point_index = stuIndex.size();
  1581. stuItemv.push_back(item);
  1582. }
  1583. if (j == 0){
  1584. x = stuItemv[0].centerx - stuItemv[0].width / 2 - 35;
  1585. y = stuItemv[0].centery - stuItemv[0].height - stuItemv[0].height / 2 - 105;
  1586. }
  1587. else if (j == page.studentcode_fill.size() - 1){
  1588. SchemaItem &item = stuItemv[stuItemv.size() - 1];
  1589. int tx = item.centerx + item.width / 2 + 35;
  1590. int ty = item.centery + item.height / 2 + 5;
  1591. w = tx - x;
  1592. h = ty - y;
  1593. }
  1594. itemcount += q_item_count;
  1595. stuGroupv.push_back(group);
  1596. }
  1597. KEGUANTI_QUESTION_LOCATEPOINT_INDEX kqli;
  1598. kqli[0] = 0;
  1599. kqli[1] = 1;
  1600. kqli[2] = 2;
  1601. kqli[3] = 3;
  1602. stuIndex.push_back(kqli);
  1603. code_tmp.centerx = x + w / 2;
  1604. code_tmp.centery = y + h / 2;
  1605. code_tmp.width = w;
  1606. code_tmp.height = h;
  1607. code_tmp.index = obj_index++;
  1608. code_tmp.nQrOrBar = 1;
  1609. code_tmp.strContent = paper_id + "_6582234412574771625_3_1_12_1_1_1";
  1610. codev.clear();
  1611. codev.push_back(code_tmp);
  1612. }
  1613. }
  1614. }
  1615. // 缺考标记
  1616. {
  1617. schema_param.quekao_item_offset_x = main_locate_point[0].x + page.absent.x*w_scale;
  1618. schema_param.quekao_item_offset_y = main_locate_point[0].y + page.absent.y*h_scale;
  1619. schema_param.quekao_item_width = page.absent.w*w_scale;
  1620. schema_param.quekao_item_height = page.absent.h*h_scale;
  1621. KEGUANTI_QUESTION_LOCATEPOINT_INDEX QKIndex;
  1622. QKIndex[0] = 0;
  1623. QKIndex[1] = 1;
  1624. QKIndex[2] = 2;
  1625. QKIndex[3] = 3;
  1626. quekaoIndex.push_back(QKIndex);
  1627. }
  1628. }
  1629. for (std::size_t i = 0; i < page.vctQuestions.size(); ++i){
  1630. question&qt = page.vctQuestions[i];
  1631. if (qt.type == 0 || qt.type == 8 || qt.type == 5){//选
  1632. SchemaGroup group;
  1633. question_count++;
  1634. group.question_code = qt.id;
  1635. static int id = 0; id = std::stoi(qt.id);
  1636. group.index = obj_index++;
  1637. group.question_index = question_count;
  1638. group.itemCount = qt.opt.size();
  1639. group.itemIndex.clear();
  1640. group.omr_out_type = ((qt.type == 0) ? OMR_OUT_TYPE::OMR_OUT_TYPE_SINGLE_NONSTRICT : ((qt.type == 8) ? OMR_OUT_TYPE::OMR_OUT_TYPE_MUTIL_STRICT : OMR_OUT_TYPE::OMR_OUT_TYPE_MUTIL_STRICT_EX));
  1641. for (int q = 0; q < group.itemCount; q++)
  1642. {
  1643. group.itemIndex.push_back(itemcount + q);
  1644. SchemaItem item;
  1645. CalcPos(qt.opt[q].pos, offset_pt, w_scale, h_scale, item.centerx, item.centery, item.width, item.height);
  1646. if (!qt.opt[q].optName.empty())
  1647. item.OutChar = qt.opt[q].optName.at(0);
  1648. item.keguanti_question_locate_point_index = keguanti_question_locatepoint_indexs.size();
  1649. itemv.push_back(item);
  1650. }
  1651. itemcount += group.itemCount;
  1652. groupv.push_back(group);
  1653. KEGUANTI_QUESTION_LOCATEPOINT_INDEX kqli;
  1654. kqli[0] = 0;
  1655. kqli[1] = 1;
  1656. kqli[2] = 2;
  1657. kqli[3] = 3;
  1658. keguanti_question_locatepoint_indexs.push_back(kqli);
  1659. }
  1660. else if (qt.type == 1 || qt.type == 2){
  1661. //通过linkparm判断第一次还是第二次出现(第一次一定小于2)
  1662. if (qt.cut.linkparm < (m_pTemplate->_version=="old" ?2:1)){
  1663. SchemaQuestionScore sqs;
  1664. sqs.type = QUESTION_SCORE_TYPE::MUTIL_SCORE;
  1665. InitScoreArea(sqs, qt.scoreBox, offset_pt, w_scale, h_scale);
  1666. if (sqs.scoreBox.type == 1){ // 1-16
  1667. sqs.count = sqs.scoreBox.limit + (m_pTemplate->_version == "old" ? 0 : 1); // 加入0 老版没有这
  1668. if (sqs.scoreBox.bPoint)
  1669. sqs.count++;
  1670. }
  1671. else if (sqs.scoreBox.type == 2){ // 29/49
  1672. sqs.count = ((int)sqs.scoreBox.limit / 10) + 12;// 12 = 各位数字+ 十/个位标记 10+2
  1673. if (sqs.scoreBox.bPoint)
  1674. sqs.count++;
  1675. }
  1676. sqs.scoreBox.bXuanZuoTi = (qt.type == 2);
  1677. sqs.index = obj_index++;
  1678. if (!qt.id.empty())
  1679. sqs.question_index = std::stoi(qt.id);
  1680. sqs.question_code = qt.id;
  1681. if (qt.type ==2){
  1682. sqs.question_code_all = qt.all_id;
  1683. sqs.question_code_temp = qt.all_id;
  1684. }
  1685. else
  1686. {
  1687. sqs.question_code_all = "";
  1688. sqs.question_code_temp = "";
  1689. }
  1690. sqs.scoreBox.maxsorce = qt.scoreBox.maxsorce;
  1691. sqs.valid_option_count = 0;
  1692. sqs.questionLocatePointIndex[0] = 0;
  1693. sqs.questionLocatePointIndex[1] = 1;
  1694. CalcPos(qt.cut.pos, offset_pt, w_scale, h_scale, sqs.centerx, sqs.centery, sqs.width, sqs.height);
  1695. if (qt.type == 2){
  1696. sqs.questionLocatePointIndex[2] = 2;
  1697. sqs.questionLocatePointIndex[3] = 3;
  1698. for (int v = 0; v < qt.selTotal && qt.opt.size() == qt.selTotal; v++)
  1699. {
  1700. CalcPos(qt.opt[v].pos, offset_pt, w_scale, h_scale, sqs.item[v].centerx, sqs.item[v].centery, sqs.item[v].width, sqs.item[v].height);
  1701. }
  1702. sqs.countItemSelete = qt.selItem;
  1703. sqs.countNum = qt.selTotal;
  1704. SetTBLR(sqs);
  1705. }
  1706. if (qt.smallQtNo == -1 || qt.smallQtNo == 0)
  1707. {
  1708. SchemaCutArea cutarea;
  1709. cutarea.index = obj_index++;
  1710. cutarea.area_name = sqs.question_code;
  1711. cutarea.isfirst = TRUE;
  1712. cutarea.question_index = sqs.question_index;
  1713. cutarea.iscut = 1;
  1714. cutarea.marktype = qt.marktype;
  1715. CalcPos(qt.cut.pos, offset_pt, w_scale, h_scale, cutarea.centerx, cutarea.centery, cutarea.width, cutarea.height);
  1716. SetTBLR(sqs);
  1717. scorev.push_back(sqs);
  1718. cutareav.push_back(cutarea);
  1719. }
  1720. else
  1721. {
  1722. SchemaCutArea cutarea;
  1723. CalcPos(qt.cut.pos, offset_pt, w_scale, h_scale, cutarea.centerx, cutarea.centery, cutarea.width, cutarea.height);
  1724. cutarea.index = obj_index++;
  1725. cutarea.isfirst = FALSE;
  1726. cutarea.question_index = -1;
  1727. cutarea.area_name = qt.id;
  1728. cutarea.marktype = qt.marktype;
  1729. SetTBLR(sqs);
  1730. scorev.push_back(sqs);
  1731. cutareav.push_back(cutarea);
  1732. }
  1733. }else{
  1734. SchemaCutArea cutarea;
  1735. CalcPos(qt.cut.pos, offset_pt, w_scale, h_scale, cutarea.centerx, cutarea.centery, cutarea.width, cutarea.height);
  1736. cutarea.index = obj_index++;
  1737. cutarea.isfirst = FALSE;
  1738. cutarea.question_index = -1;
  1739. cutarea.area_name = qt.id;
  1740. cutarea.marktype = qt.marktype;
  1741. cutareav.push_back(cutarea);
  1742. }
  1743. }
  1744. else if (qt.type == 3){
  1745. //填空(不会跨页,所以可以直接处理)
  1746. SchemaQuestionScore sqs;
  1747. sqs.type = QUESTION_SCORE_TYPE::SINGLE_SCORE;
  1748. InitScoreArea(sqs, qt.scoreBox, offset_pt, w_scale, h_scale);
  1749. sqs.count = sqs.scoreBox.vctScore.size();
  1750. if (sqs.count <= 0)
  1751. sqs.count = 1;
  1752. sqs.index = obj_index++;
  1753. if (!qt.id.empty())
  1754. sqs.question_index = std::stoi(qt.id);
  1755. sqs.scoreBox.maxsorce = qt.scoreBox.maxsorce;
  1756. sqs.question_code = qt.id;
  1757. sqs.question_code_all = "";
  1758. sqs.question_code_temp = "";
  1759. sqs.valid_option_count = 0;
  1760. sqs.questionLocatePointIndex[0] = 0;
  1761. sqs.questionLocatePointIndex[1] = 1;
  1762. CalcPos(qt.cut.pos, offset_pt, w_scale, h_scale, sqs.centerx, sqs.centery, sqs.width, sqs.height);
  1763. SchemaCutArea cutarea;
  1764. cutarea.index = obj_index++;
  1765. cutarea.area_name = sqs.question_code;
  1766. if (qt.smallQtNo == -1)
  1767. {
  1768. cutarea.isfirst = TRUE;
  1769. cutarea.iscut = 0;
  1770. }
  1771. else if (qt.smallQtNo == 0)
  1772. {
  1773. cutarea.isfirst = TRUE;
  1774. cutarea.iscut = 2;
  1775. }
  1776. else
  1777. {
  1778. cutarea.isfirst = false;
  1779. cutarea.iscut = 0;
  1780. }
  1781. cutarea.question_index = question_count;
  1782. cutarea.marktype = qt.marktype;
  1783. CalcPos(qt.cut.pos, offset_pt, w_scale, h_scale, cutarea.centerx, cutarea.centery, cutarea.width, cutarea.height);
  1784. SetTBLR(sqs);
  1785. scorev.push_back(sqs);
  1786. cutareav.push_back(cutarea);
  1787. }
  1788. else if (qt.type == 4)
  1789. {
  1790. //题组概念
  1791. //通过linkparm判断第一次还是第二次出现(第一次一定小于2)
  1792. if (qt.cut.linkparm < 1){
  1793. SchemaQuestionScore sqs;
  1794. sqs.type = QUESTION_SCORE_TYPE::MUTIL_SCORE;
  1795. InitScoreArea(sqs, qt.scoreBox, offset_pt, w_scale, h_scale);
  1796. if (sqs.scoreBox.type == 1){ // 1-16
  1797. sqs.count = sqs.scoreBox.limit + (m_pTemplate->_version == "old" ? 0 : 1); // 加入0 老版没有这
  1798. if (sqs.scoreBox.bPoint)
  1799. sqs.count++;
  1800. }
  1801. else if (sqs.scoreBox.type == 2){ // 29/49
  1802. sqs.count = ((int)sqs.scoreBox.limit / 10) + 12;// 12 = 各位数字+ 十/个位标记 10+2
  1803. if (sqs.scoreBox.bPoint)
  1804. sqs.count++;
  1805. }
  1806. sqs.index = obj_index++;
  1807. if (!qt.id.empty())
  1808. sqs.question_index = std::stoi(qt.id);
  1809. sqs.question_code = qt.id;
  1810. bool flagcreateselect = false;
  1811. sqs.question_code_temp = qt.all_id;
  1812. //设置all_id
  1813. {
  1814. std::vector<std::string> _vct_all_questions;
  1815. split(qt.all_id, (std::string)",", &_vct_all_questions);
  1816. int idfisrtindex = -1;
  1817. for (int i = 0; i < _vct_all_questions.size();i++)
  1818. {
  1819. if (_vct_all_questions[i] == qt.id)
  1820. {
  1821. idfisrtindex = i;
  1822. flagcreateselect = (i == 0) ? true : false;
  1823. }
  1824. }
  1825. sqs.question_code_all = qt.id;
  1826. for (int i = idfisrtindex + _vct_all_questions.size() / qt.selTotal; i < _vct_all_questions.size(); i += _vct_all_questions.size() / qt.selTotal)
  1827. {
  1828. sqs.question_code_all += ",";
  1829. sqs.question_code_all += _vct_all_questions[i];
  1830. }
  1831. }
  1832. sqs.scoreBox.bXuanZuoTi = flagcreateselect;
  1833. sqs.scoreBox.maxsorce = qt.scoreBox.maxsorce;
  1834. sqs.valid_option_count = 0;
  1835. sqs.questionLocatePointIndex[0] = 0;
  1836. sqs.questionLocatePointIndex[1] = 1;
  1837. CalcPos(qt.cut.pos, offset_pt, w_scale, h_scale, sqs.centerx, sqs.centery, sqs.width, sqs.height);
  1838. sqs.countItemSelete = qt.selItem;
  1839. sqs.countNum = qt.selTotal;
  1840. if (flagcreateselect){
  1841. sqs.questionLocatePointIndex[2] = 2;
  1842. sqs.questionLocatePointIndex[3] = 3;
  1843. for (int v = 0; v < qt.selTotal && qt.opt.size() == qt.selTotal; v++)
  1844. {
  1845. CalcPos(qt.opt[v].pos, offset_pt, w_scale, h_scale, sqs.item[v].centerx, sqs.item[v].centery, sqs.item[v].width, sqs.item[v].height);
  1846. }
  1847. SetTBLR(sqs);
  1848. }
  1849. if (qt.smallQtNo == -1 || qt.smallQtNo == 0)
  1850. {
  1851. SchemaCutArea cutarea;
  1852. cutarea.index = obj_index++;
  1853. cutarea.area_name = sqs.question_code;
  1854. cutarea.isfirst = TRUE;
  1855. cutarea.question_index = sqs.question_index;
  1856. cutarea.iscut = 1;
  1857. cutarea.marktype = qt.marktype;
  1858. CalcPos(qt.cut.pos, offset_pt, w_scale, h_scale, cutarea.centerx, cutarea.centery, cutarea.width, cutarea.height);
  1859. SetTBLR(sqs);
  1860. scorev.push_back(sqs);
  1861. cutareav.push_back(cutarea);
  1862. }
  1863. else
  1864. {
  1865. SchemaCutArea cutarea;
  1866. CalcPos(qt.cut.pos, offset_pt, w_scale, h_scale, cutarea.centerx, cutarea.centery, cutarea.width, cutarea.height);
  1867. cutarea.index = obj_index++;
  1868. cutarea.isfirst = FALSE;
  1869. cutarea.question_index = -1;
  1870. cutarea.area_name = qt.id;
  1871. cutarea.marktype = qt.marktype;
  1872. SetTBLR(sqs);
  1873. scorev.push_back(sqs);
  1874. cutareav.push_back(cutarea);
  1875. }
  1876. }
  1877. else{
  1878. SchemaCutArea cutarea;
  1879. CalcPos(qt.cut.pos, offset_pt, w_scale, h_scale, cutarea.centerx, cutarea.centery, cutarea.width, cutarea.height);
  1880. cutarea.index = obj_index++;
  1881. cutarea.isfirst = FALSE;
  1882. cutarea.question_index = -1;
  1883. cutarea.area_name = qt.id;
  1884. cutarea.marktype = qt.marktype;
  1885. cutareav.push_back(cutarea);
  1886. }
  1887. }
  1888. }
  1889. ////LOGI("createSchema 6");
  1890. SchemaPage* schemapage = (SchemaPage*) new SchemaPage;
  1891. SetPageDefault(*schemapage);
  1892. schemapage->schoolCardStatus = m_pTemplate->schoolCardStatus;
  1893. schemapage->isZaiXianDaTiKa = true;
  1894. schemapage->qrFlag = qrFlag;
  1895. schemapage->index = front_page ? page_index : 2;
  1896. strcpy(schemapage->paper_id, paper_id.c_str());
  1897. strcpy(schemapage->student_code, student_code.c_str());
  1898. schemapage->is_stu_id = is_stu_id;
  1899. schemapage->width = dst_img->width;
  1900. schemapage->height = dst_img->height;
  1901. schemapage->locatePointCount = main_locate_point.size();
  1902. schemapage->questionLocatePoints = questionLocatePoints;
  1903. schemapage->keguantiQuestionLocatePointIndexs = keguanti_question_locatepoint_indexs;
  1904. schemapage->stuQuestionLocatePointIndex = stuIndex;
  1905. schemapage->codeCount = codev.size();
  1906. schemapage->groupCount = groupv.size();
  1907. schemapage->itemCount = itemv.size();
  1908. schemapage->stuGroupsCount = stuGroupv.size();
  1909. schemapage->stuItemCount = stuItemv.size();
  1910. schemapage->question_score_count = scorev.size();
  1911. schemapage->cutAreaCount = cutareav.size();
  1912. int offset = sizeof(SchemaPage);
  1913. //确定上面三个定位点区域
  1914. for (std::size_t i = 0; i < main_locate_point.size(); i++)
  1915. {
  1916. SchemaLocatePoint slp;
  1917. slp.centerx = main_locate_point[i].x + main_locate_point[i].width / 2.;
  1918. slp.centery = main_locate_point[i].y + main_locate_point[i].height / 2.;
  1919. slp.width = main_locate_point[i].width;
  1920. slp.height = main_locate_point[i].height;
  1921. schemapage->locatePoints.push_back(slp);
  1922. }
  1923. schemapage->codes = codev;
  1924. schemapage->groups = groupv;
  1925. schemapage->items = itemv;
  1926. schemapage->question_score = scorev;
  1927. schemapage->cutAreas = cutareav;
  1928. schemapage->mode_type = mode_type;
  1929. schemapage->stuGroups = stuGroupv;
  1930. schemapage->stuItems = stuItemv;
  1931. schemapage->schoolCardStatus = schoolCardStatus;
  1932. //if (!m_pTemplate->useQrCode){
  1933. schemapage->is_same_exam_id = is_same_exam_id;
  1934. //}
  1935. {
  1936. std::lock_guard<std::mutex> _lck(g_mtx_examid);
  1937. schemapage->examid_by_qr_code = (g_examid_by_qr_code==1);
  1938. }
  1939. schemapage->is_front_page = front_page;
  1940. schemapage->is_use_qr_code = m_pTemplate->useQrCode;
  1941. //缺考标记相关参数
  1942. schemapage->quekao.centerx = schema_param.quekao_item_offset_x + schema_param.quekao_item_width / 2;
  1943. schemapage->quekao.centery = schema_param.quekao_item_offset_y + schema_param.quekao_item_height / 2;
  1944. schemapage->quekao.width = schema_param.quekao_item_width;
  1945. schemapage->quekao.height = schema_param.quekao_item_height;
  1946. schemapage->quekaoLocatePointIndex = quekaoIndex;
  1947. *pageSchema = schemapage;
  1948. //if (flag){
  1949. // DrawSchema(dst_img, schemapage);
  1950. // cvSaveImage(result_path, dst_img);
  1951. //}
  1952. #ifdef _draw_debug
  1953. //drawDebug(src_debug, &page);
  1954. DrawSchema(src_debug, schemapage);
  1955. {
  1956. std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds> tp = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now());
  1957. auto tmp = std::chrono::duration_cast<std::chrono::microseconds>(tp.time_since_epoch());
  1958. std::time_t timestamp = tmp.count();
  1959. std::string imagePath = g_appFilePathName + "\\image1\\";
  1960. CreateDirectoryA(imagePath.c_str(), NULL);
  1961. std::string path = imagePath + std::to_string(timestamp) + ".jpg";
  1962. cvSaveImage(path.c_str(), src_debug);
  1963. }
  1964. cvReleaseImage(&src_debug);
  1965. #endif
  1966. cvReleaseMemStorage(&storage);
  1967. cvReleaseImage(&src_gray_img);
  1968. *dst = dst_img;
  1969. ////LOGI("createSchema 7");
  1970. cvReleaseImage(&dst_gray_img);
  1971. {
  1972. cvSetImageROI(src0, roi_old);
  1973. return identify::result::IDF_SUCCESS;
  1974. }
  1975. //printf("线程:%s 单页识别结束\n", std::to_string(GetCurrentThreadId()).c_str());
  1976. }
  1977. std::string getTimeStamp()
  1978. {
  1979. std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> tp = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
  1980. auto tmp = std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
  1981. std::time_t timestamp = tmp.count();
  1982. return std::move(std::to_string(timestamp));
  1983. }
  1984. //按照指定模板进行识别
  1985. int COnLineCardPageIdentifier::Identify_impl()
  1986. {
  1987. int ret = BaseCheck();
  1988. if (ret != identify::result::IDF_SUCCESS)return ret;
  1989. InitalizeTempVar();
  1990. CvMemStorage* storage = cvCreateMemStorage(0);
  1991. IplImage * dst = NULL;
  1992. SchemaPage* pschemaPage = NULL;
  1993. std::string path = g_appFilePathName + std::string("\\image\\") + getTimeStamp() + ".jpg";
  1994. //LOGI("Identify_impl 1");
  1995. ret = createSchema(src, &dst, &pschemaPage, path.c_str(), true, m_strQrClass, m_bUseQr);
  1996. //LOGI("Identify_impl 2");
  1997. if (ret != identify::result::IDF_SUCCESS){
  1998. if (dst != NULL)cvReleaseImage(&dst);
  1999. cvReleaseMemStorage(&storage);
  2000. return ret;
  2001. }
  2002. SchemaPage& schemaPage = *pschemaPage;
  2003. omr_result->card_qrFlag = schemaPage.qrFlag;
  2004. omr_result->is_same_exam_id = schemaPage.is_same_exam_id;
  2005. omr_result->is_front_page = schemaPage.is_front_page;
  2006. omr_result->is_use_qr_code = schemaPage.is_use_qr_code;
  2007. omr_result->examid_by_qr_code = schemaPage.examid_by_qr_code;
  2008. omr_result->strMagicClassId = schemaPage.paper_id;
  2009. omr_result->strMagicStudentId = schemaPage.student_code;
  2010. /************************读取学生学号*********************************************/
  2011. ret = ReadStudentID(schemaPage, dst);
  2012. if (ret != identify::result::IDF_SUCCESS) {
  2013. if (dst != NULL)cvReleaseImage(&dst);
  2014. cvReleaseMemStorage(&storage);
  2015. if (pschemaPage != NULL)delete pschemaPage;
  2016. return ret;
  2017. }
  2018. //LOGI("Identify_impl 3");
  2019. /************************查找题目定位点,准备定位数据*********************************************/
  2020. ret = FindQuestionLocatePoints(schemaPage, dst);
  2021. if (ret != identify::result::IDF_SUCCESS) {
  2022. if (dst != NULL)cvReleaseImage(&dst);
  2023. cvReleaseMemStorage(&storage);
  2024. if (pschemaPage != NULL)delete pschemaPage;
  2025. return ret;
  2026. }
  2027. /************************客观题()*********************************************/
  2028. ret = ReadKeGuanTi1(schemaPage, dst);
  2029. if (ret != identify::result::IDF_SUCCESS) {
  2030. if (dst != NULL)cvReleaseImage(&dst);
  2031. cvReleaseMemStorage(&storage);
  2032. if (pschemaPage != NULL)delete pschemaPage;
  2033. return ret;
  2034. }
  2035. //LOGI("Identify_impl 4");
  2036. /************************阅卷读取*************************************************/
  2037. ret = ReadQuestionScore(schemaPage, dst, storage);
  2038. if (ret != identify::result::IDF_SUCCESS) {
  2039. if (dst != NULL)cvReleaseImage(&dst);
  2040. cvReleaseMemStorage(&storage);
  2041. if (pschemaPage != NULL)delete pschemaPage;
  2042. return ret;
  2043. }
  2044. //LOGI("Identify_impl 6");
  2045. /************************根据给定区域切割图片*********************************************/
  2046. ret = ClipImg(schemaPage, dst);
  2047. if (ret != identify::result::IDF_SUCCESS) {
  2048. if (dst != NULL)cvReleaseImage(&dst);
  2049. cvReleaseMemStorage(&storage);
  2050. if (pschemaPage != NULL)delete pschemaPage;
  2051. return ret;
  2052. }
  2053. //LOGI("Identify_impl 7");
  2054. /************************读取缺考标记*********************************************/
  2055. omr_result->quekaoFlag = ReadQuekaoFlag(schemaPage, dst);
  2056. omr_result->card_index = schemaPage.index;
  2057. /*
  2058. if (1){
  2059. DrawSchema(dst, pschemaPage);
  2060. cvSaveImage(path.c_str(), dst);
  2061. }
  2062. */
  2063. if (dst != NULL)cvReleaseImage(&dst);
  2064. cvReleaseMemStorage(&storage);
  2065. if (pschemaPage != NULL)delete pschemaPage;
  2066. return identify::result::IDF_SUCCESS;
  2067. }
  2068. //获取全局背景灰度,通过统计所有涂点周围像素(灰度不小于160)的灰度平均值获得
  2069. int COnLineCardPageIdentifier::caculate_global_background(SchemaPage& schemaPage, IplImage * dst, bool flag)
  2070. {
  2071. int global_background_color_count = 0;
  2072. int global_background_color_avg = 0;
  2073. int totalCount = 0;
  2074. if (!flag)
  2075. {
  2076. totalCount = schemaPage.itemCount;
  2077. }
  2078. else
  2079. {
  2080. totalCount = schemaPage.stuItemCount;
  2081. }
  2082. for (int i = 0; i<totalCount; i++)
  2083. {
  2084. SchemaItem & item = m_items[i];
  2085. RESULT_RECT result_rect;
  2086. GetRect(item.centerx, item.centery, item.width, item.height, result_rect);
  2087. int left = int(result_rect.x);
  2088. int top = int(result_rect.y);
  2089. int right = int(result_rect.x + result_rect.width);
  2090. int bottom = int(result_rect.y + result_rect.height);
  2091. int vtop = (int)(result_rect.y - (result_rect.width + 2) / 4);
  2092. int vbottom = (int)(result_rect.y + result_rect.height + (result_rect.height + 2) / 4);
  2093. int background_color_count = 0, background_color_avg = 0;
  2094. int gray;
  2095. int(*GetGray)(const IplImage * dst, int x, int y);
  2096. if (dst->nChannels == 1)GetGray = GetGrayValue;
  2097. else GetGray = GetBGRGray;
  2098. for (int x = left; x <= right; x++)
  2099. {
  2100. gray = GetGray(dst, x, vtop);
  2101. if (gray>160){ background_color_avg += gray; background_color_count++; }
  2102. gray = GetGray(dst, x, vbottom);
  2103. if (gray>160){ background_color_avg += gray; background_color_count++; }
  2104. }
  2105. background_color_avg = background_color_count>0 ? background_color_avg / background_color_count : 0;
  2106. if (background_color_avg>100){
  2107. global_background_color_avg += background_color_avg;
  2108. global_background_color_count++;
  2109. }
  2110. }
  2111. global_background_color_avg = global_background_color_count>0 ? global_background_color_avg / global_background_color_count : 0;
  2112. return global_background_color_avg;
  2113. }
  2114. //计算涂点属性
  2115. inline int COnLineCardPageIdentifier::caculate_cell_property(SchemaPage& schemaPage, SchemaItem &item, IplImage * dst, int &cellSize, double &refArea, double &avg_gray, int &grayNum, double &mo_hu_du, double &gao_heidu,/*字符区域大小*/int &char_area_size,/*字符区域黑色点数(统计选项的字符区域的灰度判定为黑色的点数,用于统计试卷该选项全局的平均字符黑点数)*/int& char_area_black_count,/*字符区域黑色点的平均灰度*/double& char_area_avg_gray, int flag)
  2116. {
  2117. int gray;//临时变量,灰度值
  2118. //int tembackcolor=max((anlyseResult.globalBackGround+200)/2,200);
  2119. int tembackcolor = (flag == 0) ? max(anlyseResult.backGroundGray - 20, 200) : max(anlyseResult.backGroundGray - 20, 0);
  2120. //获取灰度的函数指针
  2121. int(*ggray)(const IplImage * dst, int x, int y);
  2122. if (dst->nChannels == 1)ggray = GetGrayValue;
  2123. else ggray = GetBGRGray;
  2124. int left = int(item.centerx - item.width / 2. + 0.5);
  2125. int top = int(item.centery - item.height / 2. + 0.5);
  2126. int right = int(item.centerx + item.width / 2. + 0.5);
  2127. int bottom = int(item.centery + item.height / 2. + 0.5);
  2128. int vtop = (int)(item.centery - item.height*0.75 + 0.5);
  2129. /*******************统计字符区域属性************************************/
  2130. int cl = left + ((right - left + 1) + 2) / 4;
  2131. int cr = left + ((right - left + 1) * 3 + 2) / 4;
  2132. int ct = top;
  2133. int cb = bottom;
  2134. // auto rcRoi = cvRect(cl, ct, cr - cl, cb - ct);
  2135. // //auto rcRoi = cvRect(left, top, right - left, bottom - top);
  2136. // cvSetImageROI(dst, rcRoi);
  2137. // cvSaveImage("d:\\test_roi.png", dst);
  2138. //初始化字符区域参数
  2139. char_area_avg_gray = 0;
  2140. char_area_black_count = 0;
  2141. char_area_size = 0;
  2142. for (int y = ct; y <= cb; y++)
  2143. {
  2144. for (int x = cl; x <= cr; x++)
  2145. {
  2146. gray = ggray(dst, x, y);
  2147. char_area_size++;
  2148. if (gray<tembackcolor){
  2149. char_area_avg_gray += gray;
  2150. char_area_black_count++;
  2151. }
  2152. }
  2153. }
  2154. if (char_area_black_count>0)char_area_avg_gray /= char_area_black_count;
  2155. //灰度直方图
  2156. int gray256[260];
  2157. cellSize = 0;
  2158. memset(gray256, 0, sizeof(gray256));
  2159. double yRatio, xRatio, maxRatio;
  2160. double dist;
  2161. if (item.width >= item.height){
  2162. xRatio = 1.0;
  2163. yRatio = (item.width / (double)item.height)*(1 - 0.3);
  2164. if (yRatio<1)yRatio = 1;
  2165. }
  2166. else{
  2167. yRatio = 1.0;
  2168. xRatio = (item.height / (double)item.width)*(1 - 0.3);
  2169. if (xRatio<1)xRatio = 1;
  2170. }
  2171. double yd = item.centery;
  2172. double xd = item.centerx;
  2173. //理想点数
  2174. int li_xiang_dian_shu = item.width*item.height;
  2175. double dx;
  2176. double dy;
  2177. maxRatio = sqrt(xRatio*xRatio + yRatio*yRatio);
  2178. xRatio = xRatio / (item.width / 2.0);
  2179. yRatio = yRatio / (item.height / 2.0);
  2180. xRatio = xRatio / maxRatio;
  2181. yRatio = yRatio / maxRatio;
  2182. refArea = 0;
  2183. double distSum = 0;
  2184. avg_gray = 0;
  2185. grayNum = 0;
  2186. for (int y = top; y <= bottom; y++)
  2187. {
  2188. for (int x = left; x <= right; x++)
  2189. {
  2190. gray = ggray(dst, x, y);
  2191. gray256[gray]++;
  2192. cellSize++;
  2193. if (gray<tembackcolor){
  2194. avg_gray += gray;
  2195. grayNum++;
  2196. }
  2197. dx = (x - xd)*xRatio;
  2198. dy = (y - yd)*xRatio;
  2199. dist = sqrt(dx*dx + dy*dy);
  2200. gray = max(0, 255 - gray - 32);
  2201. refArea += gray*(1 - dist);
  2202. distSum += (1 - dist);
  2203. }
  2204. }
  2205. avg_gray = grayNum>0 ? avg_gray / grayNum : 256;
  2206. refArea /= 16;
  2207. refArea /= distSum;
  2208. //灰度上限
  2209. int grayUp = 256 - schemaPage.hei_du_ling_min_du * 16;
  2210. mo_hu_du = 0;
  2211. //合格黑点数
  2212. int he_ge_hei_dian_shu = 0;
  2213. for (int i = 0; i<grayUp; i++)
  2214. {
  2215. if (gray256[i]>0){
  2216. he_ge_hei_dian_shu += gray256[i];
  2217. mo_hu_du += (i*gray256[i]);
  2218. }
  2219. }
  2220. mo_hu_du = he_ge_hei_dian_shu>0 ? mo_hu_du / he_ge_hei_dian_shu : 0;
  2221. double ping_jun_hei_du = he_ge_hei_dian_shu>0 ? mo_hu_du / he_ge_hei_dian_shu : 0;
  2222. int i, endpos, flag = 0;
  2223. int hui_du_he = 0;
  2224. int hei_dian_shu = 0;
  2225. for (i = 0, endpos = grayUp; i<endpos; i++)
  2226. {
  2227. if (gray256[i]>0){
  2228. if (flag == 0){
  2229. flag = 1;
  2230. endpos = min(grayUp, i + 40);
  2231. }
  2232. hui_du_he += (i*gray256[i]);
  2233. hei_dian_shu += gray256[i];
  2234. }
  2235. if (hei_dian_shu>li_xiang_dian_shu*0.1 || hei_dian_shu >= he_ge_hei_dian_shu*0.3 + 1){
  2236. endpos = i;
  2237. i++;
  2238. break;
  2239. }
  2240. }
  2241. for (; i<grayUp&&hei_dian_shu<dianshu_meihaomi*dianshu_meihaomi / 4 + 1 && hei_dian_shu<hei_dian_shu >= he_ge_hei_dian_shu*0.3 + 1; i++)
  2242. {
  2243. hui_du_he += (i*gray256[i]);
  2244. hei_dian_shu += gray256[i];
  2245. }
  2246. endpos = i;
  2247. gao_heidu = hei_dian_shu>0 ? (255 - hui_du_he / hei_dian_shu) / 16 : 0;
  2248. refArea /= max(1.0, gao_heidu - 2);
  2249. /************确定清晰度**************************/
  2250. int pnt_high = 0, pnt_low = 0, pnt_mid = 0;
  2251. int pos1, pos2, pos3;
  2252. double minRatio = 0.3; maxRatio = 0.8;
  2253. pos1 = 255 - (int)(gao_heidu*maxRatio * 16);
  2254. for (i = 0; i <= pos1; i++)
  2255. {
  2256. pnt_high += gray256[i];
  2257. }
  2258. for (i = pos1 + 1; i<grayUp&&pnt_high<dianshu_meihaomi*dianshu_meihaomi / 4 + 1; i++)
  2259. {
  2260. pnt_high += gray256[i];
  2261. }
  2262. pos1 = i;
  2263. pos2 = hei_dian_shu*minRatio >= 3 ? 255 - (int)(gao_heidu*minRatio * 16) : 255 - 48;
  2264. pos3 = min(pos2, pos1 + 16);
  2265. for (i = pos1 + 1; i <= pos3; i++)
  2266. {
  2267. pnt_mid += gray256[i];
  2268. }
  2269. for (i = pos3 + 1; i <= pos2; i++)
  2270. {
  2271. pnt_low += gray256[i];
  2272. }
  2273. if (pnt_high == 0){ return identify::result::IDF_DIVIDE_ZERO; }
  2274. mo_hu_du = ((pnt_low + pnt_mid) / (double)pnt_high + pnt_low / (double)(pnt_high + pnt_mid)) / 2.0;
  2275. mo_hu_du = min(mo_hu_du, gao_heidu - ping_jun_hei_du);
  2276. mo_hu_du = min(min(gao_heidu, mo_hu_du), 5.0);
  2277. return identify::result::IDF_SUCCESS;
  2278. }
  2279. //分析全局属性
  2280. int COnLineCardPageIdentifier::analyseOmrPanoramic(SchemaPage& schemaPage)
  2281. {
  2282. int i;
  2283. int lev;
  2284. int count; // 所有涂点个数
  2285. int numAblePnt; // 参与分析的点的个数
  2286. double maxblk[16];
  2287. int numBlk[16];
  2288. double maxBlur[16];
  2289. int numBlur[16];
  2290. double stdBlur;
  2291. memset(numBlk, 0, sizeof(int) * 16);
  2292. memset(maxblk, 0, sizeof(double) * 16);
  2293. memset(maxBlur, 0, sizeof(double) * 16);
  2294. memset(numBlur, 0, sizeof(int) * 16);
  2295. count = schemaPage.itemCount;
  2296. numAblePnt = 0;
  2297. double& m_avaMaxBlk = anlyseResult.avgMax_heidu;
  2298. double& m_benchmarkBlk = anlyseResult.benchmarkBlk;
  2299. double& m_benchmarkArea = anlyseResult.benchmarkAreaBlk;
  2300. m_avaMaxBlk = 0;
  2301. for (i = 0; i<count; i++)
  2302. {
  2303. OnlineAnalyseResult::itemResult& itemr = anlyseResult.itemAnalyseResult[i];
  2304. if (itemr.heidu < m_benchmarkBlk || itemr.xiangdui_value < m_benchmarkArea)
  2305. continue;
  2306. if (itemr.heidu< 4.0) continue;
  2307. m_avaMaxBlk += itemr.heidu;
  2308. numAblePnt++;
  2309. lev = int(itemr.heidu);
  2310. maxblk[lev] += itemr.heidu;
  2311. numBlk[lev] ++;
  2312. lev = int(itemr.mohudu);
  2313. maxBlur[lev] += itemr.mohudu;
  2314. numBlur[lev] ++;
  2315. //pPnt++;
  2316. }
  2317. if (numAblePnt > 0)
  2318. m_avaMaxBlk /= numAblePnt;
  2319. else
  2320. m_avaMaxBlk = 12;
  2321. int stdId = 2;
  2322. int numStd = numBlk[0] + numBlk[1] + numBlk[2];
  2323. int numCur = numStd;
  2324. for (i = 3; i<16; i++)
  2325. {
  2326. numCur += (numBlk[i] - numBlk[i - 3]);
  2327. if (numCur > numStd)
  2328. {
  2329. numStd = numCur;
  2330. stdId = i;
  2331. }
  2332. }
  2333. double stdBlk = maxblk[stdId - 2] + maxblk[stdId - 1] + maxblk[stdId];
  2334. if (numStd > 0)
  2335. stdBlk /= numStd;
  2336. else
  2337. stdBlk = 12;
  2338. // 计算模糊度代表值
  2339. stdId = 2;
  2340. numStd = numBlur[0] + numBlur[1] + numBlur[2];
  2341. numCur = numStd;
  2342. for (i = 3; i<16; i++)
  2343. {
  2344. numCur += (numBlur[i] - numBlur[i - 3]);
  2345. if (numCur > numStd)
  2346. {
  2347. numStd = numCur;
  2348. stdId = i;
  2349. }
  2350. }
  2351. stdBlur = maxBlur[stdId - 2] + maxBlur[stdId - 1] + maxBlur[stdId];
  2352. if (numStd > 0)
  2353. stdBlur /= numStd;
  2354. else
  2355. stdBlur = 0;
  2356. if (stdBlur < 2.0)
  2357. stdBlk -= stdBlur;
  2358. else
  2359. stdBlk -= 2.0;
  2360. if (stdBlk < m_avaMaxBlk)
  2361. m_avaMaxBlk = stdBlk;
  2362. //统计字符区域的黑色点数的平均值
  2363. if (schemaPage.groupCount>0){
  2364. int max_item = 1;
  2365. for (int gi = 0; gi<schemaPage.groupCount; gi++)
  2366. {
  2367. if (schemaPage.groups[gi].itemCount>max_item) max_item = schemaPage.groups[gi].itemCount;
  2368. }
  2369. int * char_area_black_counts = new int[schemaPage.groupCount];
  2370. int cur_item_count;//当前选项的数量
  2371. for (int ii = 0; ii<max_item; ii++)
  2372. {
  2373. cur_item_count = 0;
  2374. long total_char_area_size = 0;
  2375. for (int gi = 0; gi<schemaPage.groupCount; gi++)
  2376. {
  2377. if (schemaPage.groups[gi].itemCount>ii){
  2378. OnlineAnalyseResult::itemResult& ir = anlyseResult.itemAnalyseResult[schemaPage.groups[gi].itemIndex[ii]];
  2379. char_area_black_counts[cur_item_count] = ir.char_area_black_count;
  2380. total_char_area_size += ir.char_area_size;
  2381. cur_item_count++;
  2382. }
  2383. }
  2384. double char_area_size_avg = total_char_area_size / (double)cur_item_count;
  2385. int temp;
  2386. for (int m = 0; m<cur_item_count; m++)
  2387. {
  2388. for (int n = m + 1; n<cur_item_count; n++)
  2389. {
  2390. if (char_area_black_counts[n]<char_area_black_counts[m]){
  2391. temp = char_area_black_counts[n];
  2392. char_area_black_counts[n] = char_area_black_counts[m];
  2393. char_area_black_counts[m] = temp;
  2394. }
  2395. }
  2396. }
  2397. anlyseResult.char_area_black_avg[ii] = -1;
  2398. if (char_area_black_counts[0] * 1.4<char_area_black_counts[cur_item_count - 1] || char_area_black_counts[cur_item_count - 1] * 1.4<char_area_size_avg){
  2399. double t = char_area_black_counts[0] * 1.15;
  2400. double f = 0;
  2401. int count__ = 0;
  2402. for (int l = 0; l<cur_item_count; l++)
  2403. {
  2404. if (t<char_area_black_counts[l]){
  2405. f += char_area_black_counts[l];
  2406. count__++;
  2407. }
  2408. }
  2409. anlyseResult.char_area_black_avg[ii] = f / count__;
  2410. }
  2411. }
  2412. delete[]char_area_black_counts;
  2413. }
  2414. return(0);
  2415. }
  2416. /************************************************************************/
  2417. /* 生成OMR涂点字符串(客观题填涂判断) 2014年11月28日10:54:19 */
  2418. /************************************************************************/
  2419. int COnLineCardPageIdentifier::GenerateOmrStr(SchemaPage& schemaPage)
  2420. {
  2421. char omr_str[512] = { 0 };
  2422. int omr_str_len = 0;
  2423. omr_result->group_result.resize(schemaPage.groups.size());
  2424. identify::result::KEGUANTI_RESULT* ketuanti_result_value = omr_result->group_result.data();
  2425. //标记是否被选中
  2426. SelectType sel[MAX_ITEM];
  2427. for (int groupIndex = 0; groupIndex<schemaPage.groupCount; groupIndex++)
  2428. {
  2429. omr_str_len = 0;
  2430. memset(sel, UNSELECT, sizeof(sel));
  2431. SchemaGroup& group = schemaPage.groups[groupIndex];
  2432. int pn = min(MAX_ITEM, group.itemCount);
  2433. OnlineAnalyseResult::itemResult* results[MAX_ITEM];
  2434. SchemaItem* items[MAX_ITEM] = { nullptr };
  2435. int maxgraynum = -1;
  2436. int mingraynum = 0xffffff;
  2437. for (int i = 0; i<pn; i++){
  2438. results[i] = &anlyseResult.itemAnalyseResult[group.itemIndex[i]];
  2439. items[i] = &m_items[group.itemIndex[i]];
  2440. if (results[i]->gray_num > maxgraynum)maxgraynum = results[i]->gray_num;
  2441. if (results[i]->gray_num < mingraynum)mingraynum = results[i]->gray_num;
  2442. }
  2443. int selected_num = 0;
  2444. int unselect_num = 0;
  2445. int uncertain_num = 0;
  2446. for (int i = 0; i<pn; i++)
  2447. {
  2448. //被涂面积小于10%
  2449. if (results[i]->gray_num<results[i]->cell_size*0.1){
  2450. sel[i] = UNSELECT;
  2451. unselect_num++;
  2452. continue;
  2453. }
  2454. //面积超过65%
  2455. if (results[i]->gray_num>results[i]->cell_size*0.65){
  2456. sel[i] = SELECTED;
  2457. selected_num++;
  2458. continue;
  2459. }
  2460. //填涂面积相差达%15,将面积不小于最大点填涂面积的总面积%10的涂点视为填涂
  2461. if (maxgraynum - mingraynum>results[i]->cell_size*0.2&&results[i]->gray_num>maxgraynum - results[i]->cell_size*0.1){
  2462. sel[i] = SELECTED;
  2463. selected_num++;
  2464. continue;
  2465. }
  2466. //填涂面积相差达%50,将面积不小于最大点填涂面积的总面积%30的涂点视为填涂
  2467. if (maxgraynum - mingraynum>results[i]->cell_size*0.5&&results[i]->gray_num>maxgraynum - results[i]->cell_size*0.3){
  2468. sel[i] = SELECTED;
  2469. selected_num++;
  2470. continue;
  2471. }
  2472. if (maxgraynum - results[i]->gray_num>results[i]->cell_size*0.2){
  2473. sel[i] = UNSELECT;
  2474. unselect_num++;
  2475. continue;
  2476. }
  2477. sel[i] = UNCERTAIN;
  2478. uncertain_num++;
  2479. }
  2480. int out_count;
  2481. identify::result::OMR_QUESTION_STATE question_state = identify::result::OMR_QUESTION_STATE::OMR_QUESTION_STATE_NORMAL;
  2482. if (group.omr_out_type == OMR_OUT_TYPE::OMR_OUT_TYPE_SINGLE_NONSTRICT){
  2483. if (selected_num>1){
  2484. int maxgrayindex = -1;
  2485. int maxgraynum = -101;
  2486. for (int i = 0; i<pn; i++)
  2487. {
  2488. if (sel[i] == SELECTED)
  2489. {
  2490. if ((results[i]->gray_num - maxgraynum>100) || (abs(results[i]->gray_num - maxgraynum) <= 100 && results[i]->heidu > results[maxgrayindex]->heidu))
  2491. {
  2492. maxgraynum = results[i]->gray_num;
  2493. maxgrayindex = i;
  2494. }
  2495. }
  2496. }
  2497. for (int i = 0; i<pn; i++)
  2498. {
  2499. if (sel[i] == SELECTED&&i != maxgrayindex){
  2500. sel[i] = UNSELECT;
  2501. }
  2502. }
  2503. }
  2504. out_count = 0;
  2505. for (int i = 0; i<pn; i++){
  2506. if (sel[i] == SELECTED){
  2507. if (out_count>0)omr_str[omr_str_len++] = schemaPage.option_spacer;
  2508. omr_str[omr_str_len++] = items[i]->OutChar;
  2509. out_count++;
  2510. }
  2511. }
  2512. if (out_count == 0){
  2513. omr_str[omr_str_len++] = schemaPage.unselect_char;
  2514. question_state = identify::result::OMR_QUESTION_STATE::OMR_QUESTION_STATE_LOUTU;
  2515. }
  2516. }
  2517. else if (group.omr_out_type == OMR_OUT_TYPE::OMR_OUT_TYPE_MUTIL_STRICT||
  2518. group.omr_out_type == OMR_OUT_TYPE::OMR_OUT_TYPE_MUTIL_STRICT_EX)
  2519. {
  2520. out_count = 0;
  2521. for (int i = 0; i < pn; i++)
  2522. {
  2523. if (sel[i] == SELECTED){
  2524. if (out_count > 0)omr_str[omr_str_len++] = schemaPage.option_spacer;
  2525. omr_str[omr_str_len++] = items[i]->OutChar;
  2526. out_count++;
  2527. }
  2528. }
  2529. if (out_count == 0){
  2530. omr_str[omr_str_len++] = schemaPage.unselect_char;
  2531. question_state = identify::result::OMR_QUESTION_STATE::OMR_QUESTION_STATE_LOUTU;
  2532. }
  2533. }
  2534. omr_str[omr_str_len] = '\0';
  2535. ketuanti_result_value[groupIndex].question_code = group.question_code;
  2536. ketuanti_result_value[groupIndex].obj_id = static_cast<unsigned int>(group.question_index);
  2537. ketuanti_result_value[groupIndex].answer = omr_str;
  2538. ketuanti_result_value[groupIndex].question_state = identify::result::OMR_QUESTION_STATE::OMR_QUESTION_STATE_NORMAL;
  2539. ketuanti_result_value[groupIndex].omr_question_type = (group.omr_out_type == OMR_OUT_TYPE::OMR_OUT_TYPE_SINGLE_NONSTRICT ?
  2540. identify::DANXUANTI : (group.omr_out_type == OMR_OUT_TYPE::OMR_OUT_TYPE_MUTIL_STRICT_EX ? identify::DUOXUANTIEX : identify::DUOXUANTI));
  2541. }
  2542. return 0;
  2543. }
  2544. // //识别指定图像
  2545. int COnLineCardPageIdentifier::Identify(const IplImage* img, void* out_result, int out_size)
  2546. {
  2547. if (out_result){
  2548. this->out_result = out_result;
  2549. this->omr_result = (identify::result::OMR_RESULT*)this->out_result;
  2550. // printf("线程:%s 缓冲区:缺考标记:%d %p\n", std::to_string(GetCurrentThreadId()).c_str(), omr_result->quekaoFlag, this->out_result);
  2551. src = (IplImage*)img;
  2552. if (src == NULL)
  2553. return identify::result::IDF_FAILURE;
  2554. }else{
  2555. return identify::result::IDF_FAILURE;
  2556. }
  2557. return Identify();
  2558. }
  2559. /************************************************************************/
  2560. /* 获取区域黑色点数量 */
  2561. /************************************************************************/
  2562. int COnLineCardPageIdentifier::GetBlackArea(const IplImage * dst)
  2563. {
  2564. int blackArea = 0;
  2565. CvRect rect = cvGetImageROI(dst);
  2566. int(*GetGray)(const IplImage * dst, int x, int y);
  2567. if (dst->nChannels == 1)GetGray = GetGrayValue;
  2568. else GetGray = GetBGRGray;
  2569. for (int y = rect.y, endy = rect.y + rect.height; y<endy; y++)
  2570. {
  2571. for (int x = rect.x, endx = rect.x + rect.width; x<endx; x++)
  2572. {
  2573. if (GetGray(dst, x, y)<180)blackArea++;
  2574. }
  2575. }
  2576. return blackArea;
  2577. }
  2578. /************************************************************************/
  2579. /*
  2580. 图像基本信息检查
  2581. 最小宽高限制
  2582. 长宽比例限制 */
  2583. /************************************************************************/
  2584. int COnLineCardPageIdentifier::BaseCheck()
  2585. {
  2586. if (src->width<200 || src->height<200){
  2587. return identify::result::IDF_SIZE2SMALL;
  2588. }
  2589. if (abs(max(src->width, src->height) / (double)min(src->width, src->height) - max(21.0, 27.9) / (double)min(21.0, 27.9))>0.2){
  2590. //图像长宽比不符
  2591. return identify::result::IDF_SIDERATIO;
  2592. }
  2593. return identify::result::IDF_SUCCESS;
  2594. }
  2595. /*
  2596. 临时变量初始化
  2597. */
  2598. void COnLineCardPageIdentifier::InitalizeTempVar()
  2599. {
  2600. m_relationKey.clear();
  2601. m_relationValue.clear();
  2602. }
  2603. // 读取学生学号
  2604. int COnLineCardPageIdentifier::ReadStudentID(SchemaPage &schemaPage, IplImage * dst)
  2605. {
  2606. omr_result->qr_result.clear();
  2607. identify::result::CODE_RESULT code_rst; code_rst.qr_str = "";
  2608. code_rst.is_stu_id = false;
  2609. if (strlen(schemaPage.student_code)>0){
  2610. code_rst.qr_str = schemaPage.student_code;
  2611. code_rst.is_stu_id = schemaPage.is_stu_id;
  2612. }else{
  2613. m_items = schemaPage.stuItems;
  2614. if (m_nBxuanxiang == 1 && schemaPage.stuGroupsCount > 0){
  2615. try{
  2616. IdentifyArea *ptr_area = new IdentifyArea(schemaPage.stuGroupsCount);
  2617. ptr_area->btiantu = true;
  2618. ptr_area->type = GROUP_TYPE_IDENTIFY::TIANTUKAOHAO;
  2619. for (int groupIndex = 0; groupIndex < schemaPage.stuGroupsCount; groupIndex++)
  2620. {
  2621. SchemaGroup& group = schemaPage.stuGroups[groupIndex];
  2622. IdentifyGroup*ptr_group = ptr_area->get_group_by_index(groupIndex);
  2623. if (ptr_group){
  2624. ptr_group->init(group.itemCount, group.question_code.c_str(), false);
  2625. for (int itemindex = 0; itemindex < group.itemCount; itemindex++){
  2626. IdentifyItem*ptr_item = ptr_group->get_item_by_index(itemindex);
  2627. if (ptr_item){
  2628. SchemaItem*ptr_sc_item = &m_items[group.itemIndex[itemindex]];
  2629. auto rc = GetCVRect(*ptr_sc_item);
  2630. ptr_item->x = rc.x;
  2631. ptr_item->y = rc.y;
  2632. ptr_item->w = rc.width;
  2633. ptr_item->h = rc.height;
  2634. ptr_item->name[0] = ptr_sc_item->OutChar;
  2635. }
  2636. }
  2637. }
  2638. }
  2639. IplImage*dst_gray_img = cvCreateImage(cvGetSize(dst), IPL_DEPTH_8U, 1);
  2640. cvCvtColor(dst, dst_gray_img, CV_BGR2GRAY);
  2641. //cvSaveImage("D:\\src_src.png", dst_gray_img);
  2642. int bret = api_ttpd_analysis_part(cv::cvarrToMat(dst_gray_img), ptr_area);
  2643. code_rst.qr_str = std::string();
  2644. for (int i = 0; i < ptr_area->group_count; ++i){
  2645. code_rst.qr_str += get_str_by_identify_group(0, ptr_area->get_group_by_index(i), schemaPage.option_spacer);
  2646. }
  2647. delete ptr_area; ptr_area = nullptr;
  2648. cvReleaseImage(&dst_gray_img); dst_gray_img = nullptr;
  2649. }
  2650. catch (...){
  2651. }
  2652. }
  2653. else{
  2654. // 计算每个填图区域图像信息
  2655. int global_background_color_avg = caculate_global_background(schemaPage, dst, true);
  2656. //模糊度,面积,高黑度,平均黑度
  2657. double mo_hu_du, refArea, gao_heidu, avg_gray;
  2658. //黑色像素数,涂点大小
  2659. int grayNum, cellSize;
  2660. //高黑度和
  2661. double topGraySum = 0;
  2662. //高黑度面积
  2663. double topGrayAreaSum = 0;
  2664. anlyseResult.backGroundGray = global_background_color_avg;
  2665. anlyseResult.cellAvgGray = 0;
  2666. anlyseResult.cellNum = 0;
  2667. int numTopGray = 0;
  2668. int ret;
  2669. item_result.resize(schemaPage.stuItemCount);
  2670. for (int i = 0; i < schemaPage.stuItemCount; i++)
  2671. {
  2672. SchemaItem & item = m_items[i];
  2673. item_result[i] = GetCVRect(item);
  2674. ret = caculate_cell_property(schemaPage, item, dst, cellSize, refArea, avg_gray, grayNum, mo_hu_du, gao_heidu, anlyseResult.itemAnalyseResult[i].char_area_size, anlyseResult.itemAnalyseResult[i].char_area_black_count, anlyseResult.itemAnalyseResult[i].char_area_avg_gray);
  2675. if (ret != identify::result::IDF_SUCCESS)return ret;
  2676. topGraySum += gao_heidu;
  2677. topGrayAreaSum += refArea;
  2678. numTopGray++;
  2679. anlyseResult.cellAvgGray += avg_gray;
  2680. anlyseResult.cellNum++;
  2681. anlyseResult.itemAnalyseResult[i].avg_gray = avg_gray;
  2682. anlyseResult.itemAnalyseResult[i].cell_size = cellSize;
  2683. anlyseResult.itemAnalyseResult[i].gray_num = grayNum;
  2684. anlyseResult.itemAnalyseResult[i].heidu = gao_heidu;
  2685. anlyseResult.itemAnalyseResult[i].mohudu = mo_hu_du;
  2686. anlyseResult.itemAnalyseResult[i].xiangdui_mianji = refArea;
  2687. anlyseResult.itemAnalyseResult[i].xiangdui_value = refArea;
  2688. }
  2689. anlyseResult.cellAvgGray = anlyseResult.cellNum > 0 ? anlyseResult.cellAvgGray / anlyseResult.cellNum : 256;
  2690. anlyseResult.avg_heidu = topGrayAreaSum > 0 ? topGraySum / topGrayAreaSum : 6;
  2691. if (numTopGray >= int(schemaPage.itemCount / 5)){
  2692. anlyseResult.float_heidu = anlyseResult.avg_heidu / schemaPage.user_float_heidu;
  2693. anlyseResult.benchmarkBlk = schemaPage.worthwhileBlk + anlyseResult.float_heidu;
  2694. }
  2695. else{
  2696. anlyseResult.benchmarkBlk = numTopGray > 0 ? min(6.0, schemaPage.worthwhileBlk + anlyseResult.avg_heidu / schemaPage.user_float_heidu) : 6;
  2697. anlyseResult.float_heidu = anlyseResult.benchmarkBlk - schemaPage.worthwhileBlk;
  2698. }
  2699. if (numTopGray > 0){
  2700. anlyseResult.avg_heidu = topGrayAreaSum / numTopGray;
  2701. anlyseResult.float_heidu = anlyseResult.avg_heidu / schemaPage.user_float_heidu;
  2702. anlyseResult.benchmarkAreaBlk = anlyseResult.float_heidu;
  2703. }
  2704. else{
  2705. anlyseResult.avg_heidu = 0;
  2706. anlyseResult.float_heidu = 0;
  2707. anlyseResult.benchmarkAreaBlk = 0.1;
  2708. }
  2709. // 获取
  2710. std::string strStudent;
  2711. if (GenerateOmrStr(schemaPage, strStudent) == 0){
  2712. code_rst.qr_str = strStudent;
  2713. }
  2714. }
  2715. }
  2716. if (!code_rst.qr_str.empty())
  2717. omr_result->qr_result.push_back(code_rst);
  2718. omr_result->online_card_paperid = schemaPage.paper_id;
  2719. omr_result->schoolCardStatus = schemaPage.schoolCardStatus;
  2720. if (m_bUseQr)
  2721. {
  2722. std::vector<std::string> split_qr;
  2723. split(m_strQrClass, (std::string)",", &split_qr);
  2724. if (split_qr.size()>1&& !split_qr[1].empty()){
  2725. omr_result->paper_id = std::stoi(split_qr[1]);
  2726. }
  2727. }
  2728. else{
  2729. omr_result->paper_id = -1;
  2730. }
  2731. return identify::result::IDF_SUCCESS;
  2732. }
  2733. //读取客观题分数
  2734. int COnLineCardPageIdentifier::ReadKeGuanTi1(SchemaPage &schemaPage, IplImage * dst)
  2735. {
  2736. m_items = schemaPage.items;
  2737. if (m_nBxuanxiang == 1 && schemaPage.groups.size() > 0){
  2738. try{
  2739. omr_result->group_result.resize(schemaPage.groups.size());
  2740. identify::result::KEGUANTI_RESULT* ketuanti_result_value = omr_result->group_result.data();
  2741. IdentifyArea *ptr_area = new IdentifyArea(schemaPage.groupCount);
  2742. ptr_area->type = GROUP_TYPE_IDENTIFY::KEGUANTI;
  2743. for (int groupIndex = 0; groupIndex < schemaPage.groupCount; groupIndex++)
  2744. {
  2745. SchemaGroup& group = schemaPage.groups[groupIndex];
  2746. IdentifyGroup*ptr_group = ptr_area->get_group_by_index(groupIndex);
  2747. if (ptr_group){
  2748. bool mul = (group.omr_out_type != OMR_OUT_TYPE::OMR_OUT_TYPE_SINGLE_NONSTRICT);
  2749. ptr_group->init(group.itemCount, group.question_code.c_str(), mul);
  2750. for (int itemindex = 0; itemindex < group.itemCount; itemindex++){
  2751. IdentifyItem*ptr_item = ptr_group->get_item_by_index(itemindex);
  2752. if (ptr_item){
  2753. SchemaItem*ptr_sc_item = &m_items[group.itemIndex[itemindex]];
  2754. auto rc = GetCVRect(*ptr_sc_item);
  2755. ptr_item->x = rc.x;
  2756. ptr_item->y = rc.y;
  2757. ptr_item->w = rc.width;
  2758. ptr_item->h = rc.height;
  2759. ptr_item->name[0] = ptr_sc_item->OutChar;
  2760. }
  2761. }
  2762. }
  2763. }
  2764. cvResetImageROI(dst);
  2765. IplImage*dst_gray_img = cvCreateImage(cvGetSize(dst), IPL_DEPTH_8U, 1);
  2766. cvCvtColor(dst, dst_gray_img, CV_BGR2GRAY);
  2767. //cvSaveImage("D:\\src_src.png", dst_gray_img);
  2768. if (0 == api_ttpd_analysis_part(cv::cvarrToMat(dst_gray_img), ptr_area)){
  2769. omr_result->group_result.resize(schemaPage.groups.size());
  2770. identify::result::KEGUANTI_RESULT* ketuanti_result_value = omr_result->group_result.data();
  2771. for (int groupIndex = 0; groupIndex < schemaPage.groupCount &&groupIndex < ptr_area->group_count; groupIndex++)
  2772. {
  2773. SchemaGroup& group = schemaPage.groups[groupIndex];
  2774. bool mul = (group.omr_out_type != OMR_OUT_TYPE::OMR_OUT_TYPE_SINGLE_NONSTRICT);
  2775. IdentifyGroup* ptr_group = ptr_area->get_group_by_index(groupIndex);
  2776. if (ptr_group->select_count == ptr_group->item_count) // 单选题如果全选,结果值会保留全部值
  2777. {
  2778. mul = true;
  2779. }
  2780. std::string omr_str = get_str_by_identify_group(mul ? 1 : 0, ptr_area->get_group_by_index(groupIndex), schemaPage.option_spacer);
  2781. ketuanti_result_value[groupIndex].question_code = group.question_code;
  2782. ketuanti_result_value[groupIndex].obj_id = static_cast<unsigned int>(group.question_index);
  2783. ketuanti_result_value[groupIndex].answer = omr_str;
  2784. ketuanti_result_value[groupIndex].question_state = identify::result::OMR_QUESTION_STATE::OMR_QUESTION_STATE_NORMAL;
  2785. ketuanti_result_value[groupIndex].omr_question_type = (group.omr_out_type == OMR_OUT_TYPE::OMR_OUT_TYPE_SINGLE_NONSTRICT ?
  2786. identify::DANXUANTI : (group.omr_out_type == OMR_OUT_TYPE::OMR_OUT_TYPE_MUTIL_STRICT_EX ? identify::DUOXUANTIEX : identify::DUOXUANTI));
  2787. }
  2788. }
  2789. cvReleaseImage(&dst_gray_img);
  2790. }
  2791. catch (cv::Exception e){
  2792. const char * ss = e.what();
  2793. return identify::result::IDF_FAILURE;
  2794. }
  2795. int global_background_color_avg = caculate_global_background(schemaPage, dst);
  2796. anlyseResult.backGroundGray = global_background_color_avg;
  2797. anlyseResult.cellAvgGray = 0;
  2798. anlyseResult.cellNum = 0;
  2799. return identify::result::IDF_SUCCESS;
  2800. }
  2801. int global_background_color_avg = caculate_global_background(schemaPage, dst);
  2802. //模糊度,面积,高黑度,平均黑度
  2803. double mo_hu_du, refArea, gao_heidu, avg_gray;
  2804. //黑色像素数,涂点大小
  2805. int grayNum, cellSize;
  2806. //高黑度和
  2807. double topGraySum = 0;
  2808. //高黑度面积
  2809. double topGrayAreaSum = 0;
  2810. anlyseResult.backGroundGray = global_background_color_avg;
  2811. anlyseResult.cellAvgGray = 0;
  2812. anlyseResult.cellNum = 0;
  2813. int numTopGray = 0;
  2814. int ret;
  2815. item_result.resize(schemaPage.itemCount);
  2816. for (int i = 0; i<schemaPage.itemCount; i++)
  2817. {
  2818. SchemaItem & item = m_items[i];
  2819. item_result[i] = GetCVRect(item);
  2820. ret = caculate_cell_property(schemaPage, item, dst, cellSize, refArea, avg_gray, grayNum, mo_hu_du, gao_heidu, anlyseResult.itemAnalyseResult[i].char_area_size, anlyseResult.itemAnalyseResult[i].char_area_black_count, anlyseResult.itemAnalyseResult[i].char_area_avg_gray);
  2821. if (ret != identify::result::IDF_SUCCESS)return ret;
  2822. topGraySum += gao_heidu;
  2823. topGrayAreaSum += refArea;
  2824. numTopGray++;
  2825. anlyseResult.cellAvgGray += avg_gray;
  2826. anlyseResult.cellNum++;
  2827. anlyseResult.itemAnalyseResult[i].avg_gray = avg_gray;
  2828. anlyseResult.itemAnalyseResult[i].cell_size = cellSize;
  2829. anlyseResult.itemAnalyseResult[i].gray_num = grayNum;
  2830. anlyseResult.itemAnalyseResult[i].heidu = gao_heidu;
  2831. anlyseResult.itemAnalyseResult[i].mohudu = mo_hu_du;
  2832. anlyseResult.itemAnalyseResult[i].xiangdui_mianji = refArea;
  2833. anlyseResult.itemAnalyseResult[i].xiangdui_value = refArea;
  2834. }
  2835. anlyseResult.cellAvgGray = anlyseResult.cellNum>0 ? anlyseResult.cellAvgGray / anlyseResult.cellNum : 256;
  2836. anlyseResult.avg_heidu = topGrayAreaSum>0 ? topGraySum / topGrayAreaSum : 6;
  2837. if (numTopGray >= int(schemaPage.itemCount / 5)){
  2838. anlyseResult.float_heidu = anlyseResult.avg_heidu / schemaPage.user_float_heidu;
  2839. anlyseResult.benchmarkBlk = schemaPage.worthwhileBlk + anlyseResult.float_heidu;
  2840. }
  2841. else{
  2842. anlyseResult.benchmarkBlk = numTopGray>0 ? min(6.0, schemaPage.worthwhileBlk + anlyseResult.avg_heidu / schemaPage.user_float_heidu) : 6;
  2843. anlyseResult.float_heidu = anlyseResult.benchmarkBlk - schemaPage.worthwhileBlk;
  2844. }
  2845. if (numTopGray>0){
  2846. anlyseResult.avg_heidu = topGrayAreaSum / numTopGray;
  2847. anlyseResult.float_heidu = anlyseResult.avg_heidu / schemaPage.user_float_heidu;
  2848. anlyseResult.benchmarkAreaBlk = anlyseResult.float_heidu;
  2849. }
  2850. else{
  2851. anlyseResult.avg_heidu = 0;
  2852. anlyseResult.float_heidu = 0;
  2853. anlyseResult.benchmarkAreaBlk = 0.1;
  2854. }
  2855. analyseOmrPanoramic(schemaPage);
  2856. GenerateOmrStr(schemaPage);
  2857. return identify::result::IDF_SUCCESS;
  2858. }
  2859. //读取填空题,和主观题分数
  2860. int COnLineCardPageIdentifier::ReadQuestionScore(SchemaPage &schemaPage, IplImage * dst, CvMemStorage* storage)
  2861. {
  2862. int tiankong_total_count = 0;
  2863. int zhuguan_total_count = 0;
  2864. for (int i = 0; i<schemaPage.question_score_count; i++){
  2865. if (schemaPage.question_score[i].type == QUESTION_SCORE_TYPE::MUTIL_SCORE)
  2866. zhuguan_total_count++;
  2867. else if (schemaPage.question_score[i].type == QUESTION_SCORE_TYPE::SINGLE_SCORE)
  2868. tiankong_total_count++;
  2869. }
  2870. omr_result->tiankongti_result.resize(tiankong_total_count);
  2871. omr_result->zhutuanti_result.resize(zhuguan_total_count);
  2872. identify::result::TIANKONGTI_RESULT*tiankongti_result_value = omr_result->tiankongti_result.data();
  2873. identify::result::ZHUGUANTI_RESULT*zhutuanti_result_value = omr_result->zhutuanti_result.data();
  2874. int score_count = 0;
  2875. int tiankong_count = 0;
  2876. for (int i = 0; i<schemaPage.question_score_count; i++){
  2877. SchemaQuestionScore& qs = schemaPage.question_score[i];
  2878. //查找题目定位点,校正题目位置
  2879. SchemaLocatePoint& lp1 = schemaPage.questionLocatePoints[qs.questionLocatePointIndex[0]];
  2880. SchemaLocatePoint& lp2 = schemaPage.questionLocatePoints[qs.questionLocatePointIndex[1]];
  2881. CvPoint2D32f point1, point2;
  2882. BOOL s1 = FindQuestionLocatePoint(dst, lp1, point1);
  2883. BOOL s2 = FindQuestionLocatePoint(dst, lp2, point2);
  2884. if (!s1&&!s2){
  2885. point1.x = lp1.centerx;
  2886. point1.y = lp1.centery;
  2887. point2.x = lp2.centerx;
  2888. point2.y = lp2.centery;
  2889. }
  2890. else if (!s1){
  2891. point1.x = lp1.centerx + (point2.x - lp2.centerx);
  2892. point1.y = lp1.centery + (point2.y - lp2.centery);
  2893. }
  2894. else if (!s2){
  2895. point2.x = lp2.centerx + (point1.x - lp1.centerx);
  2896. point2.y = lp2.centery + (point1.y - lp1.centery);
  2897. }
  2898. float data[6];
  2899. CvMat* m = caculate_scm(point1, point2, cvPoint2D32f(lp1.centerx, lp1.centery), cvPoint2D32f(lp2.centerx, lp2.centery));
  2900. memcpy(data, m->data.fl, sizeof(float) * 6);
  2901. cvReleaseMat(&m);
  2902. SchemaQuestionScore::Point * point[4] = { &qs.lt, &qs.rt, &qs.lb, &qs.rb };
  2903. float lx = -1, ly = -1;
  2904. float rx = -1, ry = -1;
  2905. double pscale = 1.0;
  2906. int redcount[30] = { 0 };
  2907. int red_in_count[30] = { 0 };
  2908. lx = data[0] * qs.lt.x + data[1] * qs.lt.y + data[2];
  2909. rx = data[0] * qs.rt.x + data[1] * qs.rt.y + data[2];
  2910. ly = data[3] * qs.lt.x + data[4] * qs.lt.y + data[5];
  2911. ry = data[3] * qs.rt.x + data[4] * qs.rt.y + data[5];
  2912. if (qs.type == QUESTION_SCORE_TYPE::MUTIL_SCORE){
  2913. if (lx >= 0 && rx >= 0){
  2914. float h = (point[2]->y - point[0]->y)*pscale;
  2915. CvRect detect_rect = cvRect(qs.scoreBox.pos.x, qs.scoreBox.pos.y, qs.scoreBox.pos.w, qs.scoreBox.pos.h);
  2916. //LOGI("GetZhuGuanTiRedCount-BEIGIN");
  2917. GetZhuGuanTiRedCount(dst, detect_rect, detect_rect, redcount, red_in_count, qs.count, qs.scoreBox.type != 1 || qs.scoreBox.bPoint, false);
  2918. //LOGI("GetZhuGuanTiRedCount-END");
  2919. float score = 0;
  2920. if (qs.scoreBox.type == 1)
  2921. {
  2922. // 小数位
  2923. if (qs.scoreBox.bPoint){
  2924. if (red_in_count[0] > 25){
  2925. score += 0.5;
  2926. }
  2927. }
  2928. // 整数位
  2929. {
  2930. int red_area = 0;
  2931. int red_area_index = -1;
  2932. for (int i = (qs.scoreBox.bPoint ? 1 : 0);
  2933. i < qs.count; ++i)
  2934. {
  2935. if (red_in_count[i]>red_area){
  2936. red_area = red_in_count[i]; red_area_index = i;
  2937. }
  2938. }
  2939. if (red_area_index >= (qs.scoreBox.bPoint ? 1 : 0)){
  2940. score += (qs.scoreBox.limit - red_area_index + (qs.scoreBox.bPoint ? 1 : 0));
  2941. }
  2942. }
  2943. }
  2944. else if (qs.scoreBox.type == 2)
  2945. {
  2946. // 小数位
  2947. if (qs.scoreBox.bPoint){
  2948. if (red_in_count[0] > 25){
  2949. score += 0.5;
  2950. }
  2951. }
  2952. {
  2953. //个位数
  2954. int red_area = 0;
  2955. int red_area_index = -1;
  2956. for (int i = (qs.scoreBox.bPoint ? 1 : 0);
  2957. i < (qs.scoreBox.bPoint ? 11 : 10); ++i)
  2958. {
  2959. if (red_in_count[i]>red_area){
  2960. red_area = red_in_count[i]; red_area_index = i;
  2961. }
  2962. }
  2963. if (red_area_index >= (qs.scoreBox.bPoint ? 1 : 0)){
  2964. score += (9 - red_area_index + (qs.scoreBox.bPoint ? 1 : 0));
  2965. }
  2966. }
  2967. {
  2968. //十位数
  2969. int red_area = 0;
  2970. int red_area_index = -1;
  2971. int begin_index = (qs.scoreBox.bPoint ? 11 : 10);
  2972. for (int i = begin_index; i < begin_index + (int)(qs.scoreBox.limit / 10) + 1; ++i)
  2973. {
  2974. if (red_in_count[i] > red_area){ red_area = red_in_count[i]; red_area_index = i; }
  2975. }
  2976. if (red_area_index >= begin_index){
  2977. score = score + 10 * ((int)(qs.scoreBox.limit / 10) - (red_area_index - begin_index) + 1);
  2978. }
  2979. }
  2980. }
  2981. if (score > qs.scoreBox.maxsorce && qs.scoreBox.maxsorce > 0)
  2982. zhutuanti_result_value[score_count].question_score = qs.scoreBox.maxsorce;
  2983. else
  2984. zhutuanti_result_value[score_count].question_score = score;
  2985. zhutuanti_result_value[score_count].question_state = identify::result::OMR_QUESTION_STATE::OMR_QUESTION_STATE_NORMAL;
  2986. }
  2987. else{
  2988. zhutuanti_result_value[score_count].question_score = 0;
  2989. zhutuanti_result_value[score_count].question_state = identify::result::OMR_QUESTION_STATE::OMR_QUESTION_STATE_WUFASHIBIE;
  2990. }
  2991. zhutuanti_result_value[score_count].obj_id = static_cast<unsigned int>(qs.question_index);
  2992. zhutuanti_result_value[score_count].maxscore = qs.scoreBox.maxsorce;
  2993. zhutuanti_result_value[score_count].question_code = qs.question_code;
  2994. zhutuanti_result_value[score_count].omr_question_type = identify::OMR_QUESTION_TYPE::ZHUTUANTI;
  2995. zhutuanti_result_value[score_count].total = 0;
  2996. zhutuanti_result_value[score_count].required = 0;
  2997. zhutuanti_result_value[score_count].xuanze = -1;
  2998. if (qs.scoreBox.bXuanZuoTi){
  2999. zhutuanti_result_value[score_count].omr_question_type = identify::OMR_QUESTION_TYPE::XUANZUOTI;
  3000. zhutuanti_result_value[score_count].total = qs.countNum;
  3001. zhutuanti_result_value[score_count].required = qs.countItemSelete;
  3002. zhutuanti_result_value[score_count].xuanze = ReadXuanZuoTi(schemaPage, qs, dst);
  3003. zhutuanti_result_value[score_count].question_code_all = qs.question_code_all;
  3004. zhutuanti_result_value[score_count].question_code_temp = qs.question_code_temp;
  3005. }
  3006. else if (qs.question_code_temp != "")
  3007. {
  3008. zhutuanti_result_value[score_count].omr_question_type = identify::OMR_QUESTION_TYPE::XUANZUOTI;
  3009. zhutuanti_result_value[score_count].total = qs.countNum;
  3010. zhutuanti_result_value[score_count].required = qs.countItemSelete;
  3011. zhutuanti_result_value[score_count].xuanze = -2;
  3012. zhutuanti_result_value[score_count].question_code_all = qs.question_code_all;
  3013. zhutuanti_result_value[score_count].question_code_temp = qs.question_code_temp;
  3014. }
  3015. score_count++;
  3016. }
  3017. else
  3018. {
  3019. if (lx >= 0 && rx >= 0){
  3020. if (qs.count > 1){
  3021. float score = 0;
  3022. int red_area_index = -1;
  3023. // 在线答题卡-填空题
  3024. if (qs.scoreBox.type == 3){
  3025. float h = (point[2]->y - point[0]->y)*pscale;
  3026. CvRect detect_rect = cvRect(qs.scoreBox.pos.x, qs.scoreBox.pos.y, qs.scoreBox.pos.w, qs.scoreBox.pos.h);
  3027. GetZhuGuanTiRedCount(dst, detect_rect, detect_rect, redcount, red_in_count, qs.count, 0, true);
  3028. int red_area = 0;
  3029. for (int m = 0; m<qs.scoreBox.vctScore.size(); m++){
  3030. if (red_in_count[m]>red_area&&red_in_count[m]>25){ red_area = red_in_count[m]; red_area_index = m; }
  3031. }
  3032. if (red_area_index >= 0 && static_cast<int>(qs.scoreBox.vctScore.size())>red_area_index){
  3033. score = qs.scoreBox.vctScore.at(qs.count - red_area_index - 1);
  3034. }
  3035. }
  3036. if (qs.scoreBox.maxsorce > 0)
  3037. {
  3038. tiankongti_result_value[tiankong_count].question_score = qs.scoreBox.maxsorce > score ? score : qs.scoreBox.maxsorce;
  3039. }
  3040. else
  3041. {
  3042. tiankongti_result_value[tiankong_count].question_score = score;
  3043. }
  3044. tiankongti_result_value[tiankong_count].maxscore = qs.scoreBox.maxsorce;
  3045. tiankongti_result_value[tiankong_count].omr_question_type = identify::OMR_QUESTION_TYPE::TIANKONGTI2;
  3046. }else{
  3047. float w = (rx - lx) / qs.count;
  3048. float h = (point[2]->y - point[0]->y)*pscale;
  3049. for (int j = 0; j<1; j++){
  3050. CvRect rect_detect = cvRect(qs.scoreBox.pos.x, qs.scoreBox.pos.y, qs.scoreBox.pos.w, qs.scoreBox.pos.h);
  3051. int red_area = GetTianKongTiRedCount(dst, rect_detect, rect_detect, 1, 0);
  3052. if (red_area > 25){
  3053. tiankongti_result_value[tiankong_count].isright = TRUE;
  3054. break;
  3055. }
  3056. else{
  3057. tiankongti_result_value[tiankong_count].isright = FALSE;
  3058. }
  3059. }
  3060. if (qs.scoreBox.maxsorce > 0)
  3061. {
  3062. tiankongti_result_value[tiankong_count].question_score = tiankongti_result_value[tiankong_count].isright ? qs.scoreBox.maxsorce : 0;
  3063. }
  3064. tiankongti_result_value[tiankong_count].maxscore = qs.scoreBox.maxsorce;
  3065. tiankongti_result_value[tiankong_count].omr_question_type = identify::OMR_QUESTION_TYPE::TIANKONGTI;
  3066. }
  3067. }else{
  3068. tiankongti_result_value[tiankong_count].maxscore = qs.scoreBox.maxsorce;
  3069. tiankongti_result_value[tiankong_count].isright = FALSE;
  3070. if (qs.scoreBox.maxsorce > 0)
  3071. {
  3072. tiankongti_result_value[tiankong_count].question_score = 0;
  3073. }
  3074. if (qs.count > 1)
  3075. {
  3076. tiankongti_result_value[tiankong_count].omr_question_type = identify::OMR_QUESTION_TYPE::TIANKONGTI2;
  3077. }
  3078. else
  3079. {
  3080. tiankongti_result_value[tiankong_count].omr_question_type = identify::OMR_QUESTION_TYPE::TIANKONGTI;
  3081. }
  3082. }
  3083. tiankongti_result_value[tiankong_count].obj_id = static_cast<unsigned int>(qs.question_index);
  3084. tiankongti_result_value[tiankong_count].question_code = qs.question_code;
  3085. tiankong_count++;
  3086. }
  3087. }
  3088. return identify::result::IDF_SUCCESS;
  3089. }
  3090. //截取图像
  3091. int COnLineCardPageIdentifier::ClipImg(SchemaPage& schemaPage, IplImage * dst)
  3092. {
  3093. cvResetImageROI(dst);
  3094. vector<int> compression_params;
  3095. compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
  3096. compression_params.push_back(60);
  3097. omr_result->cut_area_result.resize(schemaPage.cutAreaCount);
  3098. identify::result::CUT_AREA_RESULT* cut_area_result_value = omr_result->cut_area_result.data();
  3099. for (int i = 0; i<schemaPage.cutAreaCount; i++)
  3100. {
  3101. SchemaCutArea& cutArea = schemaPage.cutAreas[i];
  3102. CvRect rect = cvRect(cutArea.centerx - cutArea.width / 2, cutArea.centery - cutArea.height / 2, cutArea.width, cutArea.height);
  3103. SaveRect(rect, cut_area_result_value[i]);
  3104. IplImage* img = CutImage(dst, rect);
  3105. vector<uchar> dst;
  3106. cv::Mat _img = cvarrToMat(img);
  3107. imencode(".jpg", _img, dst, compression_params);
  3108. cut_area_result_value[i].obj_id = cutArea.index;
  3109. cut_area_result_value[i].area_index = cutArea.index;
  3110. cut_area_result_value[i].area_sub_index = cutArea.isfirst?1:0;
  3111. cut_area_result_value[i].centerx = cutArea.centerx;
  3112. cut_area_result_value[i].centery = cutArea.centery;
  3113. cut_area_result_value[i].width = cutArea.width;
  3114. cut_area_result_value[i].height = cutArea.height;
  3115. cut_area_result_value[i].area_name = cutArea.area_name;
  3116. cut_area_result_value[i].is_cut = cutArea.iscut;
  3117. cut_area_result_value[i].img_data.resize(dst.size());
  3118. memcpy(cut_area_result_value[i].img_data.data(), &dst[0], dst.size());
  3119. cvReleaseImage(&img);
  3120. }
  3121. return identify::result::IDF_SUCCESS;
  3122. }
  3123. //获取图像指定区域红色点数(主观题) 去除长直线和周边像素 减少直线边缘偏色影响
  3124. int COnLineCardPageIdentifier::GetZhuGuanTiRedCount(IplImage * dst, const CvRect& rect, const CvRect& normal_rect, int * red_counts, int * red_in_counts, int count, int mutil, bool bTianKongTi /*= false*/)
  3125. {
  3126. if (dst->nChannels != 3){ return 0; }
  3127. if (m_nXianXiaDaFenType == 1)
  3128. {
  3129. memset(red_counts, 0, sizeof(int)*count);
  3130. memset(red_in_counts, 0, sizeof(int)*count);
  3131. cvSetImageROI(dst, rect);
  3132. Mat img= cv::cvarrToMat(dst);
  3133. m_pTemplate->open_save_debug_img = 1;
  3134. if (m_pTemplate->open_save_debug_img)
  3135. cv::imwrite("D:\\image\\Debug\\GetQrCode.PNG", img);
  3136. cvResetImageROI(dst);
  3137. int tempi[50] = { 0 };
  3138. try{
  3139. EnterCriticalSection(m_althom_rcs);
  3140. // printf("线程:%s 新算法判分-开始\n", std::to_string(GetCurrentThreadId()).c_str());
  3141. if (api_red_check_analysis(img, count, bTianKongTi ? 3 : 2, mutil, tempi, count) != 0)
  3142. {
  3143. // printf("线程:%s 新算法判分-错误\n", std::to_string(GetCurrentThreadId()).c_str());
  3144. LeaveCriticalSection(m_althom_rcs);
  3145. return 0;
  3146. }
  3147. // printf("线程:%s 新算法判分-结束\n", std::to_string(GetCurrentThreadId()).c_str());
  3148. LeaveCriticalSection(m_althom_rcs);
  3149. }
  3150. catch (cv::Exception&e){
  3151. // printf("线程:%s 新算法判分-异常\n", std::to_string(GetCurrentThreadId()).c_str());
  3152. const char *error = e.what();
  3153. LeaveCriticalSection(m_althom_rcs);
  3154. }
  3155. for (int i = 0; i < count; i++)
  3156. {
  3157. red_in_counts[i] = tempi[count - i - 1];
  3158. if (red_in_counts[i] > 0)
  3159. {
  3160. red_counts[i] = 30; //目的大于25
  3161. }
  3162. }
  3163. return identify::result::IDF_SUCCESS;
  3164. }
  3165. IplImage* red = NULL;
  3166. BOOL s = GetRedBinary(dst, rect, &red);
  3167. if (!s)return 0;
  3168. IplImage * temp = cvCloneImage(red);
  3169. CvMemStorage* storage = cvCreateMemStorage();
  3170. CvSeq* contours = NULL;
  3171. cvFindContours(temp, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));
  3172. int top = normal_rect.y - rect.y;
  3173. int bottom = normal_rect.y + normal_rect.height - 1 - rect.y;
  3174. for (CvContour * c = (CvContour *)contours; c != NULL; c = (CvContour *)c->h_next) {
  3175. CvRect b_rect = cvBoundingRect(c);
  3176. if (b_rect.y>bottom - 1 || b_rect.y + b_rect.height - 1<top + 1){
  3177. cvDrawContours(red, (CvSeq *)c, cvScalar(0), cvScalar(0), 0, CV_FILLED, 8);
  3178. }
  3179. }
  3180. cvReleaseImage(&temp);
  3181. cvReleaseMemStorage(&storage);
  3182. memset(red_counts, 0, sizeof(int)*count);
  3183. memset(red_in_counts, 0, sizeof(int)*count);
  3184. int w = red->width;
  3185. int h = red->height;
  3186. for (int x = 0; x<w; x++){
  3187. int option_index = (count - 1) - x*count / w;
  3188. for (int y = 0; y<h; y++){
  3189. if (CV_IMAGE_ELEM(red, unsigned char, y, x)){
  3190. red_counts[option_index]++;
  3191. if (y <= bottom - 1 && y >= top + 1){
  3192. red_in_counts[option_index]++;
  3193. }
  3194. }
  3195. }
  3196. }
  3197. cvReleaseImage(&red);
  3198. return identify::result::IDF_SUCCESS;
  3199. }
  3200. //获取图像指定区域红色点数(填空题)
  3201. int COnLineCardPageIdentifier::GetTianKongTiRedCount(IplImage * dst, const CvRect& rect_normal, const CvRect& rect_detect,int count,int multi)
  3202. {
  3203. CvRect rect = cvGetImageROI(dst);
  3204. if (dst->nChannels != 3){ return 0; }
  3205. if (m_nXianXiaDaFenType == 1){
  3206. cvSetImageROI(dst, rect_detect);
  3207. Mat img = cv::cvarrToMat(dst);
  3208. cvResetImageROI(dst);
  3209. int tempi[50] = { 0 };
  3210. try{
  3211. EnterCriticalSection(m_althom_rcs);
  3212. // printf("线程:%s 新算法判分-开始\n", std::to_string(GetCurrentThreadId()).c_str());
  3213. int fff = api_red_check_analysis(img, count, 3, multi, tempi, count);
  3214. if (fff != 0){
  3215. // printf("线程:%s 新算法判分-错误\n", std::to_string(GetCurrentThreadId()).c_str());
  3216. LeaveCriticalSection(m_althom_rcs);
  3217. return 0;
  3218. }
  3219. // printf("线程:%s 新算法判分-结束\n", std::to_string(GetCurrentThreadId()).c_str());
  3220. LeaveCriticalSection(m_althom_rcs);
  3221. }
  3222. catch (cv::Exception&e){
  3223. // printf("线程:%s 新算法判分-异常\n", std::to_string(GetCurrentThreadId()).c_str());
  3224. LeaveCriticalSection(m_althom_rcs);
  3225. #if 0
  3226. static const char* str;
  3227. str = e.what();
  3228. #endif
  3229. }
  3230. if (tempi[0] > 0)
  3231. return 300;
  3232. return 0;
  3233. }
  3234. int w = rect_detect.width;
  3235. int h = rect_detect.height;
  3236. IplImage * red = NULL;
  3237. BOOL r = GetRedBinary(dst, rect_detect, &red);
  3238. if (!r)return 0;
  3239. vector<CvPoint2D32f> redPoints;
  3240. for (int y = 0; y<red->height; y++)
  3241. {
  3242. unsigned char * red_row_first = (unsigned char *)(red->imageData + (y*red->widthStep));
  3243. for (int x = 0; x<red->width; x++)
  3244. {
  3245. if (red_row_first[x]){
  3246. redPoints.push_back(cvPoint2D32f(x, y));
  3247. }
  3248. }
  3249. }
  3250. if (redPoints.size()==0)
  3251. {
  3252. return 0;
  3253. }
  3254. CvMemStorage * storage = cvCreateMemStorage();
  3255. CvSeq* contour = NULL;
  3256. int contours = cvFindContours(red, storage, &contour, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
  3257. int red_count = 0;
  3258. int normal_left = rect_normal.x - rect_detect.x;
  3259. int normal_top = rect_normal.y - rect_detect.y;
  3260. int normal_right = normal_left + rect_normal.width;
  3261. int normal_bottom = normal_top + rect_normal.height;
  3262. for (CvContour * c = (CvContour *)contour; c != NULL; c = (CvContour *)c->h_next){
  3263. float sum_x = 0;
  3264. float sum_y = 0;
  3265. int in_count = 0;
  3266. int area_c = 0;//轮廓在评分框内的点数
  3267. for (std::size_t i = 0; i<redPoints.size(); i++)
  3268. {
  3269. double distance = cvPointPolygonTest(c, redPoints[i], FALSE);
  3270. if (distance >= 0){
  3271. sum_x += redPoints[i].x;
  3272. sum_y += redPoints[i].y;
  3273. in_count++;
  3274. if (normal_left <= redPoints[i].x&&redPoints[i].x <= normal_right&&normal_top <= redPoints[i].y&&redPoints[i].y <= normal_bottom){
  3275. area_c++;
  3276. }
  3277. }
  3278. }
  3279. if (in_count == 0)continue;
  3280. if (area_c>60){
  3281. red_count += in_count;
  3282. continue;
  3283. }
  3284. //重心位置
  3285. float avg_x = sum_x / in_count;
  3286. float avg_y = sum_y / in_count;
  3287. if (normal_left <= avg_x&&avg_x <= normal_right + 30 && normal_top <= avg_y&&avg_y <= normal_bottom){
  3288. red_count += in_count;
  3289. }
  3290. }
  3291. cvReleaseImage(&red);
  3292. cvReleaseMemStorage(&storage);
  3293. return red_count;
  3294. }
  3295. int COnLineCardPageIdentifier::SaveLocateInfo(SchemaPage& schemaPage, vector<CvPoint2D32f> &relationKey, vector<CvPoint2D32f> &relationValue)
  3296. {
  3297. if (relationKey.size() >= 2)
  3298. {
  3299. m_relationKey = relationKey;
  3300. m_relationValue = relationValue;
  3301. double distance = 0;
  3302. int index1;
  3303. int index2;
  3304. for (std::size_t i = 0; i<m_relationKey.size(); i++)
  3305. {
  3306. for (std::size_t j = i + 1; j<m_relationKey.size(); j++)
  3307. {
  3308. double d = sqrt((m_relationKey[i].x - m_relationKey[j].x)*(m_relationKey[i].x - m_relationKey[j].x) + (m_relationKey[j].y - m_relationKey[i].y)*(m_relationKey[j].y - m_relationKey[i].y));
  3309. if (d>distance){ distance = d; index1 = i; index2 = j; }
  3310. }
  3311. }
  3312. //模板上的定位点
  3313. CvPoint2D32f *p11 = &m_relationKey[index1];
  3314. CvPoint2D32f *p12 = &m_relationKey[index2];
  3315. //试卷上的定位点
  3316. CvPoint2D32f*p21 = &m_relationValue[index1];
  3317. CvPoint2D32f*p22 = &m_relationValue[index2];
  3318. CvMat* m_m = caculate_scm(*p21, *p22, *p11, *p12);
  3319. memcpy(data, m_m->data.fl, sizeof(float) * 6);
  3320. cvReleaseMat(&m_m);
  3321. return identify::result::IDF_SUCCESS;
  3322. }
  3323. return identify::result::IDF_NOTFOUND_ENOUGH_LOCATEPOINT;
  3324. }
  3325. int COnLineCardPageIdentifier::GetRect(const int centerx, const int centery, const int width, const int height, RESULT_RECT& result_rect)
  3326. {
  3327. result_rect.x = centerx - width / 2;
  3328. result_rect.y = centery - height / 2;
  3329. result_rect.width = width;
  3330. result_rect.height = height;
  3331. return identify::result::IDF_FAILURE;
  3332. }
  3333. int COnLineCardPageIdentifier::GetRect2(const int centerx, const int centery, const int width, const int height, RESULT_RECT& result_rect)
  3334. {
  3335. double x = data[0] * centerx + data[1] * centery + data[2];
  3336. double y = data[3] * centerx + data[4] * centery + data[5];
  3337. result_rect.x = (int)(x - width / 2 + 0.5);
  3338. result_rect.y = (int)(y - height / 2 + 0.5);
  3339. result_rect.width = width;
  3340. result_rect.height = height;
  3341. return identify::result::IDF_SUCCESS;
  3342. }
  3343. template<class T>
  3344. void COnLineCardPageIdentifier::SaveRect(CvRect& rect, T& result)
  3345. {
  3346. result.centerx = static_cast<decltype(result.centerx)>(rect.x + rect.width / 2.0);
  3347. result.centery = static_cast<decltype(result.centery)>(rect.y + rect.height / 2.0);
  3348. result.width = static_cast<decltype(result.width)>(rect.width);
  3349. result.height = static_cast<decltype(result.height)>(rect.height);
  3350. result.angle = 0;
  3351. }
  3352. template<class T >
  3353. void COnLineCardPageIdentifier::DrawObjRect(IplImage * dst, T& obj_result, CvScalar& scalar)
  3354. {
  3355. cvDrawRect(dst,
  3356. cvPoint(obj_result.centerx - obj_result.width / 2, obj_result.centery - obj_result.height / 2),
  3357. cvPoint(obj_result.centerx + obj_result.width / 2, obj_result.centery + obj_result.height / 2),
  3358. scalar);
  3359. }
  3360. //查找题目定位点
  3361. BOOL COnLineCardPageIdentifier::FindQuestionLocatePoint(IplImage * dst, SchemaLocatePoint& lp1, CvPoint2D32f& point1)
  3362. {
  3363. int top = max(0, (int)(lp1.centery - lp1.height*1.5 + 0.5));
  3364. int bottom = min(dst->height - 1, (int)(lp1.centery + lp1.height*1.5 + 0.5));
  3365. int left = max(0, (int)(lp1.centerx - lp1.width*1.5 + 0.5));
  3366. int right = min(dst->width - 1, (int)(lp1.centerx + lp1.width*1.5 + 0.5));
  3367. int x = left;
  3368. int y = top;
  3369. int width = right - left + 1;
  3370. int height = bottom - top + 1;
  3371. if (width<1 || height<1)return FALSE;
  3372. IplImage* dst_gray_img = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
  3373. IplImage* dst_binary_img = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
  3374. CvMemStorage* storage = cvCreateMemStorage();
  3375. cvSetImageROI(dst, cvRect(x, y, width, height));
  3376. if (dst->nChannels == 3)cvCvtColor(dst, dst_gray_img, CV_BGR2GRAY);
  3377. else cvCopy(dst, dst_gray_img);
  3378. cvThreshold(dst_gray_img, dst_binary_img, 180, 255, CV_THRESH_BINARY);
  3379. int an = 2;
  3380. IplConvKernel * element = cvCreateStructuringElementEx(an * 2 + 1, an * 2 + 1, an, an, CV_SHAPE_RECT, 0);//创建结构元素
  3381. cvDilate(dst_binary_img, dst_binary_img, element, 1);//膨胀图像
  3382. cvErode(dst_binary_img, dst_binary_img, element, 1);//腐蚀图像
  3383. cvReleaseStructuringElement(&element);
  3384. CvSeq * pcontours = NULL;
  3385. int ncontours = cvFindContours(dst_binary_img, storage, &pcontours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
  3386. vector<CvContour*> quesiontLocatePoints;
  3387. for (CvContour * c = (CvContour *)pcontours; c != NULL; c = (CvContour *)c->h_next)
  3388. {
  3389. if (c->rect.width<lp1.width - 3)continue;
  3390. if (c->rect.height<lp1.height - 3)continue;
  3391. if (c->rect.width>lp1.width + 3)continue;
  3392. if (c->rect.height>lp1.height + 3)continue;
  3393. cvSetImageROI(dst_gray_img, c->rect);
  3394. int area = GetBlackArea(dst_gray_img);
  3395. if (area<c->rect.width*c->rect.height*0.75)continue;
  3396. quesiontLocatePoints.push_back(c);
  3397. }
  3398. double distance = 99999;
  3399. int min_index = -1;
  3400. for (std::size_t i = 0; i<quesiontLocatePoints.size(); i++)
  3401. {
  3402. double d = GetDistance(cvPoint2D32f(lp1.centerx - x, lp1.centery - y), cvPoint2D32f(quesiontLocatePoints[i]->rect.x + quesiontLocatePoints[i]->rect.width / 2.0, quesiontLocatePoints[i]->rect.y + quesiontLocatePoints[i]->rect.height / 2.0));
  3403. if (d<distance){ distance = d; min_index = i; }
  3404. }
  3405. if (min_index >= 0){
  3406. point1 = cvPoint2D32f(quesiontLocatePoints[min_index]->rect.x + quesiontLocatePoints[min_index]->rect.width / 2.0 + x, quesiontLocatePoints[min_index]->rect.y + quesiontLocatePoints[min_index]->rect.height / 2.0 + y);
  3407. cvReleaseImage(&dst_gray_img);
  3408. cvReleaseImage(&dst_binary_img);
  3409. cvReleaseMemStorage(&storage);
  3410. return TRUE;
  3411. }
  3412. cvReleaseImage(&dst_gray_img);
  3413. cvReleaseImage(&dst_binary_img);
  3414. cvReleaseMemStorage(&storage);
  3415. return FALSE;
  3416. }
  3417. double COnLineCardPageIdentifier::GetDistance(CvPoint2D32f point1, CvPoint2D32f point2)
  3418. {
  3419. double dx = point1.x - point2.x;
  3420. double dy = point1.y - point2.y;
  3421. return sqrt(dx*dx + dy*dy);
  3422. }
  3423. int COnLineCardPageIdentifier::FindQuestionLocatePoints(SchemaPage& schemaPage, IplImage * dst)
  3424. {
  3425. std::vector<SchemaLocatePoint>& questionLocatePoints = schemaPage.questionLocatePoints;
  3426. m_question_locate_points.resize(questionLocatePoints.size());
  3427. m_question_locate_point_found.resize(questionLocatePoints.size());
  3428. for (std::size_t i = 0; i<questionLocatePoints.size(); i++)
  3429. {
  3430. m_question_locate_point_found[i] = FindQuestionLocatePoint(dst, questionLocatePoints[i], m_question_locate_points[i]);
  3431. }
  3432. return identify::result::IDF_SUCCESS;
  3433. }
  3434. BOOL COnLineCardPageIdentifier::GetRedBinary(IplImage * dst, const CvRect& rect_detect, IplImage ** red_binary)
  3435. {
  3436. #define GETREDBINARY_DEBUG 0
  3437. #define rename_image(img,new_name) IplImage * new_name = img; img = NULL;
  3438. if (dst == NULL || dst->nChannels != 3)return FALSE;
  3439. int w = rect_detect.width;
  3440. int h = rect_detect.height;
  3441. IplImage * hsv = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 3);
  3442. //存储灰度图像和二值化图像
  3443. IplImage * gray = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1);
  3444. IplImage * black = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1);
  3445. IplImage * black_dilate = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1);
  3446. //记录较浅一些的红色
  3447. IplImage * red_low = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1);
  3448. //记录较深一些的红色
  3449. IplImage * red_high = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1);
  3450. IplImage * red = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1);
  3451. cvSetImageROI(dst, rect_detect);
  3452. #if GETREDBINARY_DEBUG
  3453. cvSaveImage("D:\\dst.png", dst);
  3454. #endif
  3455. cvCvtColor(dst, hsv, CV_BGR2HSV);
  3456. cvCvtColor(dst, gray, CV_BGR2GRAY);
  3457. cvAdaptiveThreshold(gray, gray, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV, 9, 10.0);
  3458. #ifdef _DEBUG
  3459. cvSaveImage("D:\\red_high.png", gray);
  3460. #endif
  3461. rename_image(gray, binary);
  3462. #define HSV_VALUE_H hsv_row_first[hsv_offset]
  3463. #define HSV_VALUE_S hsv_row_first[hsv_offset+1]
  3464. #define HSV_VALUE_V hsv_row_first[hsv_offset+2]
  3465. const int hsv_v_valve = 255 * 50 / 100;
  3466. const int hsv_h_max_valve = 180 * 20 / 360;
  3467. const int hsv_h_min_valve = 180 * 315 / 360;
  3468. const int hsv_s_valve_1 = 43;
  3469. const int hsv_s_valve_2 = 255 * 33 / 100;
  3470. const int hsv_valve_high = 255 * (23 + 70) / 100;
  3471. const int hsv_valve_low = 255 * (13 + 60) / 100;
  3472. for (int y = 0; y<h; y++)
  3473. {
  3474. unsigned char * hsv_row_first = (unsigned char *)(hsv->imageData + y*hsv->widthStep);
  3475. unsigned char * red1_row_first = (unsigned char *)(red_low->imageData + y*red_low->widthStep);
  3476. unsigned char * red2_row_first = (unsigned char *)(red_high->imageData + y*red_high->widthStep);
  3477. unsigned char * binary_row_first = (unsigned char *)(binary->imageData + y*binary->widthStep);
  3478. unsigned char * black_row_first = (unsigned char *)(black->imageData + y*black->widthStep);
  3479. for (int x = 0, hsv_offset = 0; x<w; x++, hsv_offset += 3)
  3480. {
  3481. if (HSV_VALUE_V >= hsv_v_valve && (HSV_VALUE_H >= hsv_h_min_valve || HSV_VALUE_H <= hsv_h_max_valve)){
  3482. red1_row_first[x] = (HSV_VALUE_S >= hsv_s_valve_1 && (HSV_VALUE_S + HSV_VALUE_V) >= hsv_valve_low) ? 255 : 0;
  3483. red2_row_first[x] = (HSV_VALUE_S >= hsv_s_valve_2 && (HSV_VALUE_S + HSV_VALUE_V) >= hsv_valve_high) ? HSV_VALUE_S : 0;
  3484. }
  3485. else{
  3486. red1_row_first[x] = red2_row_first[x] = 0;
  3487. }
  3488. black_row_first[x] = (binary_row_first[x] && !red1_row_first[x]) ? 255 : 0;
  3489. }
  3490. }
  3491. #if GETREDBINARY_DEBUG
  3492. cvSaveImage("D:\\hsv.png", hsv);
  3493. cvSaveImage("D:\\red_low.png", red_low);
  3494. cvSaveImage("D:\\red_high.png", red_high);
  3495. cvSaveImage("D:\\binary.png", binary);
  3496. cvSaveImage("D:\\black.png", black);
  3497. #endif
  3498. cvThreshold(red_high, red_high, 0, 255, CV_THRESH_OTSU);
  3499. #ifdef _DEBUG
  3500. cvSaveImage("D:\\red_high.png", red_high);
  3501. #endif
  3502. int an = 1;
  3503. IplConvKernel * element = cvCreateStructuringElementEx(an * 2 + 1, an * 2 + 1, an, an, CV_SHAPE_RECT, 0);//创建结构元素
  3504. cvDilate(binary, binary, element, 2);//膨胀图像
  3505. cvDilate(red_high, red_high, element, 2);//膨胀图像
  3506. cvDilate(black, black_dilate, element, 2);//膨胀图像
  3507. for (int y = 0; y<h; y++)
  3508. {
  3509. unsigned char * binary_row_first = (unsigned char *)(binary->imageData + y*binary->widthStep);
  3510. unsigned char * red1_row_first = (unsigned char *)(red_low->imageData + y*red_low->widthStep);
  3511. unsigned char * red2_row_first = (unsigned char *)(red_high->imageData + y*red_high->widthStep);
  3512. unsigned char * red_row_first = (unsigned char *)(red->imageData + y*red->widthStep);
  3513. unsigned char * black_dilate_row_first = (unsigned char *)(black_dilate->imageData + y*black_dilate->widthStep);
  3514. for (int x = 0; x<w; x++)
  3515. {
  3516. red_row_first[x] = (red1_row_first[x] && !black_dilate_row_first[x] && ((!binary_row_first[x]) || red2_row_first[x])) ? 255 : 0;
  3517. }
  3518. }
  3519. rename_image(red_high, red_dilate);
  3520. cvDilate(red, red_dilate, element, 2);//膨胀图像
  3521. for (int y = 0; y<h; y++)
  3522. {
  3523. unsigned char * red1_row_first = (unsigned char *)(red_low->imageData + y*red_low->widthStep);
  3524. unsigned char * red_row_first = (unsigned char *)(red->imageData + y*red->widthStep);
  3525. unsigned char * black_row_first = (unsigned char *)(black->imageData + y*black->widthStep);
  3526. unsigned char * red_dilate_row_first = (unsigned char *)(red_dilate->imageData + y*red_dilate->widthStep);
  3527. for (int x = 0; x<w; x++)
  3528. {
  3529. red_row_first[x] = (red_row_first[x] || (red_dilate_row_first[x] && (red1_row_first[x] && !black_row_first[x]))) ? 255 : 0;
  3530. }
  3531. }
  3532. cvDilate(red, red_dilate, element, 1);//膨胀图像
  3533. for (int y = 0; y<h; y++)
  3534. {
  3535. unsigned char * red_row_first = (unsigned char *)(red->imageData + y*red->widthStep);
  3536. unsigned char * black_row_first = (unsigned char *)(black->imageData + y*black->widthStep);
  3537. unsigned char * red_dilate_row_first = (unsigned char *)(red_dilate->imageData + y*red_dilate->widthStep);
  3538. for (int x = 0; x<w; x++)
  3539. {
  3540. if (!red_row_first[x] && black_row_first[x] && red_dilate_row_first[x]){
  3541. red_row_first[x] = 255;
  3542. }
  3543. }
  3544. }
  3545. cvReleaseStructuringElement(&element);
  3546. *red_binary = red;
  3547. cvReleaseImage(&hsv);
  3548. cvReleaseImage(&binary);
  3549. cvReleaseImage(&black);
  3550. cvReleaseImage(&black_dilate);
  3551. cvReleaseImage(&red_low);
  3552. cvReleaseImage(&red_dilate);
  3553. return TRUE;
  3554. }
  3555. int COnLineCardPageIdentifier::mycaculate_global_background(SchemaItem items[], int itemCount, IplImage * dst)
  3556. {
  3557. int global_background_color_count = 0;
  3558. int global_background_color_avg = 0;
  3559. for (int i = 0; i<itemCount; i++)
  3560. {
  3561. //SchemaItem & item = schemaPage.items[i];
  3562. SchemaItem & item = items[i];
  3563. RESULT_RECT result_rect;
  3564. GetRect(item.centerx, item.centery, item.width, item.height, result_rect);
  3565. int left = int(result_rect.x);
  3566. int top = int(result_rect.y);
  3567. int right = int(result_rect.x + result_rect.width);
  3568. int bottom = int(result_rect.y + result_rect.height);
  3569. int vtop = (int)(result_rect.y - (result_rect.width + 2) / 4);
  3570. int vbottom = (int)(result_rect.y + result_rect.height + (result_rect.height + 2) / 4);
  3571. int background_color_count = 0, background_color_avg = 0;
  3572. int gray;
  3573. int(*GetGray)(const IplImage * dst, int x, int y);
  3574. if (dst->nChannels == 1)GetGray = GetGrayValue;
  3575. else GetGray = GetBGRGray;
  3576. for (int x = left; x <= right; x++)
  3577. {
  3578. gray = GetGray(dst, x, vtop);
  3579. if (gray>160){ background_color_avg += gray; background_color_count++; }
  3580. gray = GetGray(dst, x, vbottom);
  3581. if (gray>160){ background_color_avg += gray; background_color_count++; }
  3582. }
  3583. background_color_avg = background_color_count>0 ? background_color_avg / background_color_count : 0;
  3584. if (background_color_avg>100){
  3585. global_background_color_avg += background_color_avg;
  3586. global_background_color_count++;
  3587. }
  3588. }
  3589. global_background_color_avg = global_background_color_count>0 ? global_background_color_avg / global_background_color_count : 0;
  3590. return global_background_color_avg;
  3591. }
  3592. //选做题分析全局属性
  3593. int COnLineCardPageIdentifier::myanalyseOmrPanoramic(OnlineAnalyseResult& anlyseResultTemp, int count)
  3594. {
  3595. int i;
  3596. int lev;
  3597. //int count; // 所有涂点个数
  3598. int numAblePnt; // 参与分析的点的个数
  3599. double maxblk[16];
  3600. int numBlk[16];
  3601. double maxBlur[16];
  3602. int numBlur[16];
  3603. double stdBlur;
  3604. memset(numBlk, 0, sizeof(int) * 16);
  3605. memset(maxblk, 0, sizeof(double) * 16);
  3606. memset(maxBlur, 0, sizeof(double) * 16);
  3607. memset(numBlur, 0, sizeof(int) * 16);
  3608. //count = schemaPage.itemCount;
  3609. numAblePnt = 0;
  3610. double& m_avaMaxBlk = anlyseResultTemp.avgMax_heidu;
  3611. double& m_benchmarkBlk = anlyseResultTemp.benchmarkBlk;
  3612. double& m_benchmarkArea = anlyseResultTemp.benchmarkAreaBlk;
  3613. m_avaMaxBlk = 0;
  3614. for (i = 0; i<count; i++)
  3615. {
  3616. OnlineAnalyseResult::itemResult& itemr = anlyseResultTemp.itemAnalyseResult[i];
  3617. if (itemr.heidu < m_benchmarkBlk || itemr.xiangdui_value < m_benchmarkArea)
  3618. continue;
  3619. if (itemr.heidu< 4.0) continue;
  3620. m_avaMaxBlk += itemr.heidu;
  3621. numAblePnt++;
  3622. lev = int(itemr.heidu);
  3623. maxblk[lev] += itemr.heidu;
  3624. numBlk[lev] ++;
  3625. lev = int(itemr.mohudu);
  3626. maxBlur[lev] += itemr.mohudu;
  3627. numBlur[lev] ++;
  3628. //pPnt++;
  3629. }
  3630. if (numAblePnt > 0)
  3631. m_avaMaxBlk /= numAblePnt;
  3632. else
  3633. m_avaMaxBlk = 12;
  3634. int stdId = 2;
  3635. int numStd = numBlk[0] + numBlk[1] + numBlk[2];
  3636. int numCur = numStd;
  3637. for (i = 3; i<16; i++)
  3638. {
  3639. numCur += (numBlk[i] - numBlk[i - 3]);
  3640. if (numCur > numStd)
  3641. {
  3642. numStd = numCur;
  3643. stdId = i;
  3644. }
  3645. }
  3646. double stdBlk = maxblk[stdId - 2] + maxblk[stdId - 1] + maxblk[stdId];
  3647. if (numStd > 0)
  3648. stdBlk /= numStd;
  3649. else
  3650. stdBlk = 12;
  3651. // 计算模糊度代表值
  3652. stdId = 2;
  3653. numStd = numBlur[0] + numBlur[1] + numBlur[2];
  3654. numCur = numStd;
  3655. for (i = 3; i<16; i++)
  3656. {
  3657. numCur += (numBlur[i] - numBlur[i - 3]);
  3658. if (numCur > numStd)
  3659. {
  3660. numStd = numCur;
  3661. stdId = i;
  3662. }
  3663. }
  3664. stdBlur = maxBlur[stdId - 2] + maxBlur[stdId - 1] + maxBlur[stdId];
  3665. if (numStd > 0)
  3666. stdBlur /= numStd;
  3667. else
  3668. stdBlur = 0;
  3669. if (stdBlur < 2.0)
  3670. stdBlk -= stdBlur;
  3671. else
  3672. stdBlk -= 2.0;
  3673. if (stdBlk < m_avaMaxBlk)
  3674. m_avaMaxBlk = stdBlk;
  3675. //统计字符区域的黑色点数的平均值
  3676. int max_item = count;
  3677. int * char_area_black_counts = new int[1];
  3678. int cur_item_count;//当前选项的数量
  3679. for (int ii = 0; ii<max_item; ii++)
  3680. {
  3681. cur_item_count = 0;
  3682. long total_char_area_size = 0;
  3683. for (int gi = 0; gi<1; gi++)
  3684. {
  3685. if (max_item > ii){
  3686. OnlineAnalyseResult::itemResult & ir = anlyseResultTemp.itemAnalyseResult[ii];
  3687. char_area_black_counts[cur_item_count] = ir.char_area_black_count;
  3688. total_char_area_size += ir.char_area_size;
  3689. cur_item_count++;
  3690. }
  3691. }
  3692. double char_area_size_avg = total_char_area_size / (double)cur_item_count;
  3693. int temp;
  3694. for (int m = 0; m<cur_item_count; m++)
  3695. {
  3696. for (int n = m + 1; n<cur_item_count; n++)
  3697. {
  3698. if (char_area_black_counts[n]<char_area_black_counts[m]){
  3699. temp = char_area_black_counts[n];
  3700. char_area_black_counts[n] = char_area_black_counts[m];
  3701. char_area_black_counts[m] = temp;
  3702. }
  3703. }
  3704. }
  3705. anlyseResultTemp.char_area_black_avg[ii] = -1;
  3706. if (char_area_black_counts[0] * 1.4<char_area_black_counts[cur_item_count - 1] || char_area_black_counts[cur_item_count - 1] * 1.4<char_area_size_avg){
  3707. double t = char_area_black_counts[0] * 1.15;
  3708. double f = 0;
  3709. int count__ = 0;
  3710. for (int l = 0; l<cur_item_count; l++)
  3711. {
  3712. if (t<char_area_black_counts[l]){
  3713. f += char_area_black_counts[l];
  3714. count__++;
  3715. }
  3716. }
  3717. anlyseResultTemp.char_area_black_avg[ii] = f / count__;
  3718. }
  3719. }
  3720. delete[]char_area_black_counts;
  3721. return(0);
  3722. }
  3723. /************************************************************************/
  3724. /* 获取选做题选择项 */
  3725. /************************************************************************/
  3726. int COnLineCardPageIdentifier::myGenerateOmrStr(OnlineAnalyseResult& anlyseResultTemp, int count)
  3727. {
  3728. int omr_str_len = 0;
  3729. //标记是否被选中
  3730. SelectType sel[MAX_ITEM] = { SelectType::UNSELECT };
  3731. int pn = min(MAX_ITEM, count);
  3732. OnlineAnalyseResult::itemResult* results[MAX_ITEM];
  3733. for (int i = 0; i<pn; i++){
  3734. results[i] = &anlyseResultTemp.itemAnalyseResult[i];
  3735. }
  3736. int maxgraynum = -1;
  3737. int mingraynum = 0xffffff;
  3738. for (int i = 0; i<pn; i++)
  3739. {
  3740. if (results[i]->gray_num>maxgraynum)maxgraynum = results[i]->gray_num;
  3741. if (results[i]->gray_num<mingraynum)mingraynum = results[i]->gray_num;
  3742. }
  3743. int selected_num = 0;
  3744. int unselect_num = 0;
  3745. int uncertain_num = 0;
  3746. for (int i = 0; i<pn; i++)
  3747. {
  3748. //被涂面积小于10%
  3749. if (results[i]->gray_num<results[i]->cell_size*0.1){
  3750. sel[i] = UNSELECT;
  3751. unselect_num++;
  3752. continue;
  3753. }
  3754. //面积超过65%
  3755. if (results[i]->gray_num>results[i]->cell_size*0.65){
  3756. sel[i] = SELECTED;
  3757. selected_num++;
  3758. continue;
  3759. }
  3760. //填涂面积相差达%15,将面积不小于最大点填涂面积的总面积%10的涂点视为填涂
  3761. if (maxgraynum - mingraynum>results[i]->cell_size*0.15&&results[i]->gray_num>maxgraynum - results[i]->cell_size*0.1){
  3762. sel[i] = SELECTED;
  3763. selected_num++;
  3764. continue;
  3765. }
  3766. //填涂面积相差达%50,将面积不小于最大点填涂面积的总面积%30的涂点视为填涂
  3767. if (maxgraynum - mingraynum>results[i]->cell_size*0.5&&results[i]->gray_num>maxgraynum - results[i]->cell_size*0.3){
  3768. sel[i] = SELECTED;
  3769. selected_num++;
  3770. continue;
  3771. }
  3772. if (maxgraynum - results[i]->gray_num>results[i]->cell_size*0.2){
  3773. sel[i] = UNSELECT;
  3774. unselect_num++;
  3775. continue;
  3776. }
  3777. sel[i] = UNCERTAIN;
  3778. uncertain_num++;
  3779. }
  3780. identify::result::OMR_QUESTION_STATE question_state = identify::result::OMR_QUESTION_STATE::OMR_QUESTION_STATE_NORMAL;
  3781. if (selected_num>1){
  3782. int maxgrayindex = -1;
  3783. int maxgraynum = -101;
  3784. for (int i = 0; i<pn; i++){
  3785. if (sel[i] == SELECTED){
  3786. if ((results[i]->gray_num - maxgraynum > 100) || (abs(results[i]->gray_num - maxgraynum) <= 100 && results[i]->heidu > results[maxgrayindex]->heidu))
  3787. {
  3788. maxgraynum = results[i]->gray_num;
  3789. maxgrayindex = i;
  3790. }
  3791. }
  3792. }
  3793. for (int i = 0; i<pn; i++){
  3794. if (sel[i] == SELECTED&&i != maxgrayindex){
  3795. sel[i] = UNSELECT;
  3796. }
  3797. }
  3798. }
  3799. for (int i = 0; i<pn; i++){
  3800. if (sel[i] == SELECTED){
  3801. return i;
  3802. }
  3803. }
  3804. return -1;
  3805. }
  3806. //读取选做题选项数据
  3807. int COnLineCardPageIdentifier::ReadXuanZuoTi(SchemaPage& schemaPage, SchemaQuestionScore& qs, IplImage * dst)
  3808. {
  3809. if (m_nBxuanxiang == 1){
  3810. auto m_items = qs.item;
  3811. try{
  3812. IdentifyArea *ptr_area = new IdentifyArea(1);
  3813. ptr_area->type = GROUP_TYPE_IDENTIFY::XUANZUOTI;
  3814. IdentifyGroup*ptr_group = ptr_area->get_group_by_index(0);
  3815. if (ptr_group){
  3816. ptr_group->init(qs.countNum, "", false);
  3817. for (int itemindex = 0; itemindex < qs.countNum; itemindex++){
  3818. SchemaItem & item = qs.item[itemindex];
  3819. IdentifyItem*ptr_item = ptr_group->get_item_by_index(itemindex);
  3820. if (ptr_item){
  3821. SchemaItem*ptr_sc_item = &item;
  3822. auto rc = GetCVRect(*ptr_sc_item);
  3823. ptr_item->x = rc.x;
  3824. ptr_item->y = rc.y;
  3825. ptr_item->w = rc.width;
  3826. ptr_item->h = rc.height;
  3827. ptr_item->name[0] = ptr_sc_item->OutChar;
  3828. }
  3829. }
  3830. }
  3831. auto roi = cvGetImageROI(dst);
  3832. cvResetImageROI(dst);
  3833. IplImage*dst_gray_img = cvCreateImage(cvGetSize(dst), IPL_DEPTH_8U, 1);
  3834. cvCvtColor(dst, dst_gray_img, CV_BGR2GRAY);
  3835. //cv::imwrite("d:\\exception.png", cv::cvarrToMat(dst_gray_img));
  3836. int bret = api_ttpd_analysis_part(cv::cvarrToMat(dst_gray_img), ptr_area);
  3837. int n_ret = -1;
  3838. if (ptr_group&&ptr_group->select){
  3839. for (int i = 0; i < ptr_group->item_count; ++i){
  3840. int *ptr_int = ptr_group->select + i;
  3841. auto ptr_tmp = ptr_group->get_item_by_index(i);
  3842. if (*ptr_int == 1 && ptr_tmp){
  3843. n_ret = i;
  3844. break;
  3845. }
  3846. }
  3847. }
  3848. cvSetImageROI(dst, roi);
  3849. delete ptr_area; ptr_area = nullptr;
  3850. cvReleaseImage(&dst_gray_img); dst_gray_img = nullptr;
  3851. return n_ret;
  3852. }
  3853. catch (cv::Exception e){
  3854. const char * er = e.what();
  3855. return -1;
  3856. }
  3857. return -1;
  3858. }
  3859. else{
  3860. int global_background_color_avg = mycaculate_global_background(qs.item, qs.countNum, dst);
  3861. //模糊度,面积,高黑度,平均黑度
  3862. double mo_hu_du, refArea, gao_heidu, avg_gray;
  3863. //黑色像素数,涂点大小
  3864. int grayNum, cellSize;
  3865. //高黑度和
  3866. double topGraySum = 0;
  3867. //高黑度面积
  3868. double topGrayAreaSum = 0;
  3869. OnlineAnalyseResult anlyseResultTemp;
  3870. anlyseResultTemp.backGroundGray = global_background_color_avg;
  3871. anlyseResultTemp.cellAvgGray = 0;
  3872. anlyseResultTemp.cellNum = 0;
  3873. int numTopGray = 0;
  3874. int ret;
  3875. for (int i = 0; i < qs.countNum; i++)
  3876. {
  3877. SchemaItem & item = qs.item[i];
  3878. ret = caculate_cell_property(schemaPage, item, dst, cellSize, refArea, avg_gray, grayNum, mo_hu_du, gao_heidu, anlyseResultTemp.itemAnalyseResult[i].char_area_size, anlyseResultTemp.itemAnalyseResult[i].char_area_black_count, anlyseResultTemp.itemAnalyseResult[i].char_area_avg_gray);
  3879. if (ret != identify::result::IDF_SUCCESS)return ret;
  3880. topGraySum += gao_heidu;
  3881. topGrayAreaSum += refArea;
  3882. numTopGray++;
  3883. anlyseResultTemp.cellAvgGray += static_cast<int>(avg_gray);
  3884. anlyseResultTemp.cellNum++;
  3885. anlyseResultTemp.itemAnalyseResult[i].avg_gray = static_cast<int>(avg_gray);
  3886. anlyseResultTemp.itemAnalyseResult[i].cell_size = cellSize;
  3887. anlyseResultTemp.itemAnalyseResult[i].gray_num = grayNum;
  3888. anlyseResultTemp.itemAnalyseResult[i].heidu = gao_heidu;
  3889. anlyseResultTemp.itemAnalyseResult[i].mohudu = mo_hu_du;
  3890. anlyseResultTemp.itemAnalyseResult[i].xiangdui_mianji = refArea;
  3891. anlyseResultTemp.itemAnalyseResult[i].xiangdui_value = refArea;
  3892. }
  3893. anlyseResultTemp.cellAvgGray = anlyseResultTemp.cellNum > 0 ? anlyseResultTemp.cellAvgGray / anlyseResultTemp.cellNum : 256;
  3894. anlyseResultTemp.avg_heidu = topGrayAreaSum > 0 ? topGraySum / topGrayAreaSum : 6;
  3895. if (numTopGray >= int(schemaPage.itemCount / 5)){
  3896. anlyseResultTemp.float_heidu = anlyseResultTemp.avg_heidu / schemaPage.user_float_heidu;
  3897. anlyseResultTemp.benchmarkBlk = schemaPage.worthwhileBlk + anlyseResultTemp.float_heidu;
  3898. }
  3899. else{
  3900. anlyseResultTemp.benchmarkBlk = numTopGray > 0 ? min(6.0, schemaPage.worthwhileBlk + anlyseResultTemp.avg_heidu / schemaPage.user_float_heidu) : 6;
  3901. anlyseResultTemp.float_heidu = anlyseResultTemp.benchmarkBlk - schemaPage.worthwhileBlk;
  3902. }
  3903. if (numTopGray > 0){
  3904. anlyseResultTemp.avg_heidu = topGrayAreaSum / numTopGray;
  3905. anlyseResultTemp.float_heidu = anlyseResultTemp.avg_heidu / schemaPage.user_float_heidu;
  3906. anlyseResultTemp.benchmarkAreaBlk = anlyseResultTemp.float_heidu;
  3907. }
  3908. else{
  3909. anlyseResultTemp.avg_heidu = 0;
  3910. anlyseResultTemp.float_heidu = 0;
  3911. anlyseResultTemp.benchmarkAreaBlk = 0.1;
  3912. }
  3913. int r = myanalyseOmrPanoramic(anlyseResultTemp, qs.countNum);
  3914. r = myGenerateOmrStr(anlyseResultTemp, qs.countNum);
  3915. return r;
  3916. }
  3917. }
  3918. int COnLineCardPageIdentifier::GenerateOmrStr(SchemaPage& schemaPage, string &ret)
  3919. {
  3920. char omr_str[512] = { 0 };
  3921. //标记是否被选中
  3922. SelectType sel[200] = { SelectType::UNSELECT };
  3923. for (int groupIndex = 0; groupIndex<schemaPage.stuGroupsCount; groupIndex++)
  3924. {
  3925. int omr_str_len = 0;
  3926. memset(sel, UNSELECT, sizeof(sel));
  3927. SchemaGroup& group = schemaPage.stuGroups[groupIndex];
  3928. int pn = min(200, group.itemCount);
  3929. OnlineAnalyseResult::itemResult* results[200];
  3930. SchemaItem* items[200];
  3931. int maxgraynum = -1;
  3932. int mingraynum = 0xffffff;
  3933. for (int i = 0; i<pn; i++){
  3934. results[i] = &anlyseResult.itemAnalyseResult[group.itemIndex[i]];
  3935. items[i] = &m_items[group.itemIndex[i]];
  3936. if (results[i]->gray_num > maxgraynum)maxgraynum = results[i]->gray_num;
  3937. if (results[i]->gray_num < mingraynum)mingraynum = results[i]->gray_num;
  3938. }
  3939. int selected_num = 0;
  3940. int unselect_num = 0;
  3941. int uncertain_num = 0;
  3942. for (int i = 0; i<pn; i++)
  3943. {
  3944. //面积超过65%
  3945. if (results[i]->gray_num>results[i]->cell_size*0.65){
  3946. sel[i] = SELECTED;
  3947. selected_num++;
  3948. continue;
  3949. }
  3950. //填涂面积相差达%20,将面积不小于最大点填涂面积的总面积%10的涂点视为填涂
  3951. if (maxgraynum - mingraynum>results[i]->cell_size*0.2&&results[i]->gray_num>maxgraynum - results[i]->cell_size*0.1){
  3952. sel[i] = SELECTED;
  3953. selected_num++;
  3954. continue;
  3955. }
  3956. //填涂面积相差达%50,将面积不小于最大点填涂面积的总面积%30的涂点视为填涂
  3957. if (maxgraynum - mingraynum>results[i]->cell_size*0.5&&results[i]->gray_num>maxgraynum - results[i]->cell_size*0.3){
  3958. sel[i] = SELECTED;
  3959. selected_num++;
  3960. continue;
  3961. }
  3962. sel[i] = UNCERTAIN;
  3963. uncertain_num++;
  3964. }
  3965. if (group.omr_out_type == OMR_OUT_TYPE::OMR_OUT_TYPE_SINGLE_NONSTRICT){
  3966. if (selected_num > 1){
  3967. int maxgrayindex = -1;
  3968. int maxgraynum = -101;
  3969. int countSel = 0;
  3970. for (int i = 0; i < pn; i++)
  3971. {
  3972. if (sel[i] == SELECTED)
  3973. {
  3974. countSel++;
  3975. if ((results[i]->gray_num - maxgraynum>100) || (abs(results[i]->gray_num - maxgraynum) <= 100 && results[i]->heidu > results[maxgrayindex]->heidu))
  3976. {
  3977. maxgraynum = results[i]->gray_num;
  3978. maxgrayindex = i;
  3979. }
  3980. }
  3981. }
  3982. for (int i = 0; i < pn; i++)
  3983. {
  3984. if (sel[i] == SELECTED&&i != maxgrayindex){
  3985. sel[i] = UNSELECT;
  3986. }
  3987. }
  3988. }
  3989. int out_count = 0;
  3990. for (int i = 0; i < pn; i++)
  3991. {
  3992. if (sel[i] == SELECTED){
  3993. if (out_count > 0)omr_str[omr_str_len++] = schemaPage.option_spacer;
  3994. omr_str[omr_str_len++] = items[i]->OutChar;
  3995. out_count++;
  3996. }
  3997. }
  3998. if (omr_str_len != 1){
  3999. return 1;
  4000. }
  4001. omr_str[omr_str_len] = '\0';
  4002. ret += omr_str;
  4003. }
  4004. }
  4005. return 0;
  4006. }
  4007. //读取缺考标记
  4008. bool COnLineCardPageIdentifier::ReadQuekaoFlag(SchemaPage &schemaPage, IplImage * dst)
  4009. {
  4010. if (schemaPage.quekaoLocatePointIndex.size() < 1)
  4011. return false;
  4012. SchemaItem item;
  4013. item.centerx = schemaPage.quekao.centerx;
  4014. item.centery = schemaPage.quekao.centery;
  4015. item.width = schemaPage.quekao.width;
  4016. item.height = schemaPage.quekao.height;
  4017. int cellSize, grayNum, char_area_size, char_area_black_count;
  4018. double refArea, avg_gray, mo_hu_du, gao_heidu, char_area_avg_gray;
  4019. if (schemaPage.itemCount == 0 && schemaPage.stuQuestionLocatePointIndex.size() < 1)
  4020. {
  4021. anlyseResult.backGroundGray = 225;
  4022. }
  4023. int ret = caculate_cell_property(schemaPage, item, dst, cellSize, refArea, avg_gray, grayNum, mo_hu_du, gao_heidu, char_area_size, char_area_black_count, char_area_avg_gray);
  4024. OnlineAnalyseResult anlyseResult;
  4025. anlyseResult.cellAvgGray += static_cast<int>(avg_gray);
  4026. anlyseResult.cellNum++;
  4027. anlyseResult.itemAnalyseResult[0].avg_gray = static_cast<int>(avg_gray);
  4028. anlyseResult.itemAnalyseResult[0].cell_size = cellSize;
  4029. anlyseResult.itemAnalyseResult[0].gray_num = grayNum;
  4030. anlyseResult.itemAnalyseResult[0].heidu = gao_heidu;
  4031. anlyseResult.itemAnalyseResult[0].mohudu = mo_hu_du;
  4032. anlyseResult.itemAnalyseResult[0].xiangdui_mianji = refArea;
  4033. anlyseResult.itemAnalyseResult[0].xiangdui_value = refArea;
  4034. //标记是否被选中
  4035. SelectType sel = UNSELECT;
  4036. OnlineAnalyseResult::itemResult* results;
  4037. results = &anlyseResult.itemAnalyseResult[0];
  4038. int maxgraynum = -1;
  4039. int mingraynum = 0xffffff;
  4040. if (results->gray_num>maxgraynum)maxgraynum = results->gray_num;
  4041. if (results->gray_num<mingraynum)mingraynum = results->gray_num;
  4042. //面积超过65%
  4043. if (results->gray_num>results->cell_size*0.65){
  4044. sel = SELECTED;
  4045. return true;
  4046. }
  4047. //填涂面积相差达%20,将面积不小于最大点填涂面积的总面积%10的涂点视为填涂
  4048. if (maxgraynum - mingraynum>results->cell_size*0.2&&results->gray_num>maxgraynum - results->cell_size*0.1){
  4049. sel = SELECTED;
  4050. return true;
  4051. }
  4052. //填涂面积相差达%50,将面积不小于最大点填涂面积的总面积%30的涂点视为填涂
  4053. if (maxgraynum - mingraynum>results->cell_size*0.5&&results->gray_num>maxgraynum - results->cell_size*0.3){
  4054. sel = SELECTED;
  4055. return true;
  4056. }
  4057. return false;
  4058. }
  4059. void COnLineCardPageIdentifier::DrawSchema(IplImage*dst_img, SchemaPage* & pageSchema)
  4060. {
  4061. // 绘制定位点
  4062. for (std::size_t i = 0; i < pageSchema->questionLocatePoints.size(); i++){
  4063. cvDrawRect(dst_img,
  4064. cvPoint(pageSchema->questionLocatePoints[i].centerx - pageSchema->questionLocatePoints[i].width / 2.0, pageSchema->questionLocatePoints[i].centery - pageSchema->questionLocatePoints[i].height / 2.0),
  4065. cvPoint(pageSchema->questionLocatePoints[i].centerx + pageSchema->questionLocatePoints[i].width / 2.0, pageSchema->questionLocatePoints[i].centery + pageSchema->questionLocatePoints[i].height / 2.0),
  4066. cvScalar(0, 255, 0));
  4067. }
  4068. // 绘制二维码 条形码
  4069. for (std::size_t i = 0; i < pageSchema->codes.size(); i++){
  4070. cvDrawRect(dst_img,
  4071. cvPoint(pageSchema->codes[i].centerx - pageSchema->codes[i].width / 2.0, pageSchema->codes[i].centery - pageSchema->codes[i].height / 2.0),
  4072. cvPoint(pageSchema->codes[i].centerx + pageSchema->codes[i].width / 2.0, pageSchema->codes[i].centery + pageSchema->codes[i].height / 2.0),
  4073. cvScalar(0, 255, 0));
  4074. }
  4075. // 绘制
  4076. for (std::size_t i = 0; i < pageSchema->items.size(); i++){
  4077. cvDrawRect(dst_img,
  4078. cvPoint(pageSchema->items[i].centerx - pageSchema->items[i].width / 2.0, pageSchema->items[i].centery - pageSchema->items[i].height / 2.0),
  4079. cvPoint(pageSchema->items[i].centerx + pageSchema->items[i].width / 2.0, pageSchema->items[i].centery + pageSchema->items[i].height / 2.0),
  4080. cvScalar(0, 255, 0));
  4081. }
  4082. // 主观题
  4083. for (std::size_t i = 0; i < pageSchema->question_score.size(); i++){
  4084. if (pageSchema->question_score[i].scoreBox.bXuanZuoTi){
  4085. for (int j = 0; j < pageSchema->question_score[i].countNum; j++){
  4086. cvDrawRect(dst_img,
  4087. cvPoint(pageSchema->question_score[i].item[j].centerx - pageSchema->question_score[i].item[j].width / 2.0, pageSchema->question_score[i].item[j].centery - pageSchema->question_score[i].item[j].height / 2.0),
  4088. cvPoint(pageSchema->question_score[i].item[j].centerx + pageSchema->question_score[i].item[j].width / 2.0, pageSchema->question_score[i].item[j].centery + pageSchema->question_score[i].item[j].height / 2.0),
  4089. cvScalar(0, 255, 0));
  4090. }
  4091. }
  4092. // 绘制打分区域
  4093. int x = pageSchema->question_score[i].scoreBox.pos.x,
  4094. y = pageSchema->question_score[i].scoreBox.pos.y,
  4095. w = pageSchema->question_score[i].scoreBox.pos.w,
  4096. h = pageSchema->question_score[i].scoreBox.pos.h;
  4097. cvDrawRect(dst_img,
  4098. cvPoint(x, y),
  4099. cvPoint(x + w, y + h),
  4100. cvScalar(0, 0,255));
  4101. }
  4102. // 剪裁区域
  4103. for (std::size_t i = 0; i < pageSchema->cutAreas.size(); ++i)
  4104. {
  4105. cvDrawRect(dst_img,
  4106. cvPoint(pageSchema->cutAreas[i].centerx - pageSchema->cutAreas[i].width / 2.0, pageSchema->cutAreas[i].centery - pageSchema->cutAreas[i].height / 2.0),
  4107. cvPoint(pageSchema->cutAreas[i].centerx + pageSchema->cutAreas[i].width / 2.0, pageSchema->cutAreas[i].centery + pageSchema->cutAreas[i].height / 2.0),
  4108. cvScalar(0, 255, 0));
  4109. }
  4110. // 学号
  4111. for (std::size_t i = 0; i < pageSchema->stuItems.size(); i++){
  4112. cvDrawRect(dst_img,
  4113. cvPoint(pageSchema->stuItems[i].centerx - pageSchema->stuItems[i].width / 2.0, pageSchema->stuItems[i].centery - pageSchema->stuItems[i].height / 2.0),
  4114. cvPoint(pageSchema->stuItems[i].centerx + pageSchema->stuItems[i].width / 2.0, pageSchema->stuItems[i].centery + pageSchema->stuItems[i].height / 2.0),
  4115. cvScalar(0, 255, 0));
  4116. }
  4117. //缺考标识
  4118. if (pageSchema->quekaoLocatePointIndex.size()>0){
  4119. cvDrawRect(dst_img,
  4120. cvPoint(pageSchema->quekao.centerx - pageSchema->quekao.width / 2.0, pageSchema->quekao.centery - pageSchema->quekao.height / 2.0),
  4121. cvPoint(pageSchema->quekao.centerx + pageSchema->quekao.width / 2.0, pageSchema->quekao.centery + pageSchema->quekao.height / 2.0),
  4122. cvScalar(0, 0, 255));
  4123. }
  4124. }
  4125. }