CvxText.cpp 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327
  1. #include "pch.h"
  2. #include "CvxText.h"
  3. #include <json/json.h>
  4. #include "BaseUtility.h"
  5. #include <iostream>
  6. #include <fstream>
  7. #if QQM_ADD
  8. #include "cvUtil.h"
  9. #endif
  10. using namespace std;
  11. using namespace cv;
  12. #if defined(GNUC)
  13. #pragma GCC diagnostic push
  14. #pragma GCC diagnostic ignored “-Wdeprecated-declarations”
  15. #elif defined(_MSC_VER)
  16. #pragma warning(disable : 4996)
  17. #endif
  18. void GetStringSize(HDC hDC, const char* str, int* w, int* h)
  19. {
  20. SIZE size;
  21. GetTextExtentPoint32A(hDC, str, strlen(str), &size);
  22. if (w != 0) *w = size.cx;
  23. if (h != 0) *h = size.cy;
  24. }
  25. cv::Size GetTextSize(const char* str, int fontSize, const char* fn, bool italic, bool underline)
  26. {
  27. HDC hDC = CreateCompatibleDC(0);
  28. LOGFONTA lf;
  29. lf.lfHeight = -fontSize;
  30. lf.lfWidth = 0;
  31. lf.lfEscapement = 0;
  32. lf.lfOrientation = 0;
  33. lf.lfWeight = 5;
  34. lf.lfItalic = italic; //斜体
  35. lf.lfUnderline = underline; //下划线
  36. lf.lfStrikeOut = 0;
  37. lf.lfCharSet = DEFAULT_CHARSET;
  38. lf.lfOutPrecision = 0;
  39. lf.lfClipPrecision = 0;
  40. lf.lfQuality = PROOF_QUALITY;
  41. lf.lfPitchAndFamily = 0;
  42. strcpy_s(lf.lfFaceName, fn);
  43. HFONT hf = CreateFontIndirectA(&lf);
  44. HFONT hOldFont = (HFONT)SelectObject(hDC, hf);
  45. int strBaseW = 0, strBaseH = 0;
  46. int singleRow = 0;
  47. char buf[1 << 12];
  48. strcpy_s(buf, str);
  49. char *bufT[1 << 12]; // 这个用于分隔字符串后剩余的字符,可能会超出。
  50. //处理多行
  51. {
  52. int nnh = 0;
  53. int cw, ch;
  54. const char* ln = strtok_s(buf, "\n", bufT);
  55. while (ln != 0)
  56. {
  57. GetStringSize(hDC, ln, &cw, &ch);
  58. strBaseW = max(strBaseW, cw);
  59. strBaseH = max(strBaseH, ch);
  60. ln = strtok_s(0, "\n", bufT);
  61. nnh++;
  62. }
  63. singleRow = strBaseH;
  64. strBaseH *= nnh;
  65. }
  66. SelectObject(hDC, hOldFont);
  67. DeleteObject(hf);
  68. DeleteDC(hDC);
  69. cv::Size size;
  70. size.width = strBaseW;
  71. size.height = strBaseH;
  72. return size;
  73. }
  74. void putTextZH(cv::Mat &dst, cv::Size & rSize, const char* str, Point org, Scalar color, int fontSize, const char* fn, bool italic, bool underline)
  75. {
  76. CV_Assert(dst.data != 0 && (dst.channels() == 1 || dst.channels() == 3));
  77. int x, y, r, b;
  78. if (org.x > dst.cols || org.y > dst.rows) return;
  79. x = org.x < 0 ? -org.x : 0;
  80. y = org.y < 0 ? -org.y : 0;
  81. LOGFONTA lf;
  82. lf.lfHeight = -fontSize;
  83. lf.lfWidth = 0;
  84. lf.lfEscapement = 0;
  85. lf.lfOrientation = 0;
  86. lf.lfWeight = 5;
  87. lf.lfItalic = italic; //斜体
  88. lf.lfUnderline = underline; //下划线
  89. lf.lfStrikeOut = 0;
  90. lf.lfCharSet = DEFAULT_CHARSET;
  91. lf.lfOutPrecision = 0;
  92. lf.lfClipPrecision = 0;
  93. lf.lfQuality = PROOF_QUALITY;
  94. lf.lfPitchAndFamily = 0;
  95. strcpy_s(lf.lfFaceName, fn);
  96. HFONT hf = CreateFontIndirectA(&lf);
  97. HDC hDC = CreateCompatibleDC(0);
  98. HFONT hOldFont = (HFONT)SelectObject(hDC, hf);
  99. int strBaseW = 0, strBaseH = 0;
  100. int singleRow = 0;
  101. char buf[1 << 12];
  102. strcpy_s(buf, str);
  103. char *bufT[1 << 12]; // 这个用于分隔字符串后剩余的字符,可能会超出。
  104. //处理多行
  105. {
  106. int nnh = 0;
  107. int cw, ch;
  108. const char* ln = strtok_s(buf, "\n", bufT);
  109. while (ln != 0)
  110. {
  111. GetStringSize(hDC, ln, &cw, &ch);
  112. strBaseW = max(strBaseW, cw);
  113. strBaseH = max(strBaseH, ch);
  114. ln = strtok_s(0, "\n", bufT);
  115. nnh++;
  116. }
  117. singleRow = strBaseH;
  118. strBaseH *= nnh;
  119. }
  120. rSize.width = strBaseW;
  121. rSize.height = strBaseH;
  122. if (org.x + strBaseW < 0 || org.y + strBaseH < 0)
  123. {
  124. SelectObject(hDC, hOldFont);
  125. DeleteObject(hf);
  126. DeleteObject(hDC);
  127. return;
  128. }
  129. r = org.x + strBaseW > dst.cols ? dst.cols - org.x - 1 : strBaseW - 1;
  130. b = org.y + strBaseH > dst.rows ? dst.rows - org.y - 1 : strBaseH - 1;
  131. org.x = org.x < 0 ? 0 : org.x;
  132. org.y = org.y < 0 ? 0 : org.y;
  133. BITMAPINFO bmp = { 0 };
  134. BITMAPINFOHEADER& bih = bmp.bmiHeader;
  135. int strDrawLineStep = strBaseW * 3 % 4 == 0 ? strBaseW * 3 : (strBaseW * 3 + 4 - ((strBaseW * 3) % 4));
  136. bih.biSize = sizeof(BITMAPINFOHEADER);
  137. bih.biWidth = strBaseW;
  138. bih.biHeight = strBaseH;
  139. bih.biPlanes = 1;
  140. bih.biBitCount = 24;
  141. bih.biCompression = BI_RGB;
  142. bih.biSizeImage = strBaseH * strDrawLineStep;
  143. bih.biClrUsed = 0;
  144. bih.biClrImportant = 0;
  145. void* pDibData = 0;
  146. HBITMAP hBmp = CreateDIBSection(hDC, &bmp, DIB_RGB_COLORS, &pDibData, 0, 0);
  147. CV_Assert(pDibData != 0);
  148. HBITMAP hOldBmp = (HBITMAP)SelectObject(hDC, hBmp);
  149. //color.val[2], color.val[1], color.val[0]
  150. SetTextColor(hDC, RGB(255, 255, 255));
  151. SetBkColor(hDC, 0);
  152. //SetStretchBltMode(hDC, COLORONCOLOR);
  153. strcpy_s(buf, str);
  154. const char* ln = strtok_s(buf, "\n", bufT);
  155. int outTextY = 0;
  156. while (ln != 0)
  157. {
  158. TextOutA(hDC, 0, outTextY, ln, strlen(ln));
  159. outTextY += singleRow;
  160. ln = strtok_s(0, "\n", bufT);
  161. }
  162. uchar* dstData = (uchar*)dst.data;
  163. int dstStep = dst.step / sizeof(dstData[0]);
  164. unsigned char* pImg = (unsigned char*)dst.data + org.x * dst.channels() + org.y * dstStep;
  165. unsigned char* pStr = (unsigned char*)pDibData + x * 3;
  166. for (int tty = y; tty <= b; ++tty)
  167. {
  168. unsigned char* subImg = pImg + (tty - y) * dstStep;
  169. unsigned char* subStr = pStr + (strBaseH - tty - 1) * strDrawLineStep;
  170. for (int ttx = x; ttx <= r; ++ttx)
  171. {
  172. for (int n = 0; n < dst.channels(); ++n) {
  173. double vtxt = subStr[n] / 255.0;
  174. int cvv = vtxt * color.val[n] + (1 - vtxt) * subImg[n];
  175. subImg[n] = cvv > 255 ? 255 : (cvv < 0 ? 0 : cvv);
  176. }
  177. subStr += 3;
  178. subImg += dst.channels();
  179. }
  180. }
  181. SelectObject(hDC, hOldBmp);
  182. SelectObject(hDC, hOldFont);
  183. DeleteObject(hf);
  184. DeleteObject(hBmp);
  185. DeleteDC(hDC);
  186. }
  187. ///////////////////////////// 数据收集卡 ///////////////////////////////////////
  188. // 获取字符串的画布上的宽度
  189. int getLineStrWidth(string str, int fontSize, int ttBoxW, int tiSl, int backPix) {
  190. int iw = str.length()*fontSize*0.5;
  191. iw += ttBoxW;
  192. iw += tiSl;
  193. iw += backPix;
  194. iw += fontSize * 1.5; // 题号的宽度 最多不超过1.5个字体宽度 56.
  195. return iw;
  196. }
  197. // 转码 utf-8 2 ansi
  198. static void UTF82ANSI(LPCSTR lpBuff, int nLen, char* pData, int iMaxLen)
  199. {
  200. ZeroMemory(pData, sizeof(char)*iMaxLen);
  201. int nCont = MultiByteToWideChar(CP_UTF8, 0, lpBuff, nLen, NULL, 0);
  202. WCHAR* szTemp = new WCHAR[nCont + 1];
  203. ZeroMemory(szTemp, sizeof(WCHAR)*(nCont + 1));
  204. MultiByteToWideChar(CP_UTF8, 0, lpBuff, nLen, szTemp, nCont);
  205. //获取缓冲区大小,并申请空间,缓冲区大小事按字节计算的
  206. int len = WideCharToMultiByte(CP_ACP, 0, szTemp, nCont, NULL, 0, NULL, NULL);
  207. if (len < iMaxLen) {
  208. WideCharToMultiByte(CP_ACP, 0, szTemp, nCont, pData, len, NULL, NULL);
  209. }
  210. else {
  211. char* buffer = new char[len + 1];
  212. //宽字节编码转换成多字节编码
  213. WideCharToMultiByte(CP_ACP, 0, szTemp, nCont, buffer, len, NULL, NULL);
  214. buffer[len] = '\0';
  215. //删除缓冲区并返回值
  216. strncpy(pData, buffer, iMaxLen - 1);
  217. delete[] buffer;
  218. buffer = NULL;
  219. }
  220. delete[]szTemp;
  221. szTemp = NULL;
  222. }
  223. // 二进制码生成获取
  224. void createBinString(Mat & img, int pageNum, int ptw, int pth, cv::Point ptStart, vector<cv::Rect>& vecBoxPages) {
  225. vector<int> vecBinStr; vecBinStr.resize(12);
  226. for (int i = 11; i >= 0; i--) {
  227. int ys = pageNum % 2;
  228. vecBinStr[i] = ys;
  229. pageNum = pageNum / 2;
  230. }
  231. vecBoxPages.clear();
  232. int ptPgW = ptw / 2; int ptPgH = pth / 2;
  233. for (int j = 0; j < 3; j++) {
  234. int _startY = ptStart.y + 15 + 50 * j;
  235. for (int i = 0; i < 4; i++) {
  236. int _startX = ptStart.x + 18 + i * 72;
  237. vecBoxPages.push_back(cv::Rect(_startX, _startY, ptPgW, ptPgH));
  238. if (vecBinStr[j * 4 + i])
  239. rectangle(img, vecBoxPages[vecBoxPages.size() - 1], cv::Scalar(0), -1);
  240. else
  241. rectangle(img, vecBoxPages[vecBoxPages.size() - 1], cv::Scalar(200, 200, 200), 2, 8, 0);
  242. }
  243. }
  244. return;
  245. }
  246. void generatePageJson(vector<cv::Rect>& vecPts, vector<cv::Rect>& vecBoxPages)
  247. {
  248. Json::Value imageSize;
  249. imageSize["width"] = 1654;
  250. imageSize["height"] = 2344;
  251. Json::Value location(Json::arrayValue);
  252. for (auto& iter : vecPts)
  253. {
  254. Json::Value item;
  255. item["x"] = iter.x;
  256. item["y"] = iter.y;
  257. item["width"] = iter.width;
  258. item["height"] = iter.height;
  259. location.append(item);
  260. }
  261. Json::Value pagenumber(Json::arrayValue);
  262. int nSubVecSize = 4;// 每个小vector的容量
  263. for (size_t i = 0, j = 1; i < vecBoxPages.size(); i += nSubVecSize)
  264. {
  265. vector<cv::Rect> vecSmall;
  266. auto last = std::min(vecBoxPages.size(), i + nSubVecSize);
  267. vecSmall.insert(vecSmall.begin(), vecBoxPages.begin() + i, vecBoxPages.begin() + last);
  268. Json::Value opt(Json::arrayValue);
  269. std::string choice[] = { "A", "B", "C", "D" };
  270. for (int h = 0; h < vecSmall.size(); h++)
  271. {
  272. Json::Value bin;
  273. bin["x"] = vecSmall[h].x;
  274. bin["y"] = vecSmall[h].y;
  275. bin["width"] = vecSmall[h].width;
  276. bin["height"] = vecSmall[h].height;
  277. bin["optName"] = choice[h];
  278. opt.append(bin);
  279. }
  280. Json::Value item;
  281. item["id"] = j;
  282. item["opt"] = opt;
  283. pagenumber.append(item);
  284. j++;
  285. }
  286. Json::Value itemRoot;
  287. itemRoot["imageSize"] = imageSize;
  288. itemRoot["location"] = location;
  289. itemRoot["pagenumber"] = pagenumber;
  290. Json::FastWriter writer;
  291. std::string strJson = writer.write(itemRoot);
  292. CFile zip;
  293. zip.Open(_T("D:\\page.json"), CFile::modeCreate | CFile::modeWrite);
  294. DWORD wide_string_len = MultiByteToWideChar(CP_ACP, 0, strJson.c_str(), -1, NULL, 0);
  295. WCHAR* wide_string = new WCHAR[wide_string_len];
  296. wide_string_len = MultiByteToWideChar(CP_ACP, 0, strJson.c_str(), -1, wide_string, wide_string_len);
  297. DWORD utf8_string_len = WideCharToMultiByte(CP_UTF8, 0, wide_string, -1, NULL, 0, NULL, NULL);
  298. CHAR* utf8_string = new CHAR[utf8_string_len];
  299. utf8_string_len = WideCharToMultiByte(CP_UTF8, 0, wide_string, -1, utf8_string, utf8_string_len, NULL, NULL);
  300. zip.Write((void*)utf8_string, utf8_string_len - 1);
  301. // LOG4CPLUS_INFO_FMT(pTestLogger, LOG4CPLUS_TEXT("%s"), CString(json_str.c_str()));
  302. delete wide_string;
  303. delete utf8_string;
  304. zip.Close();
  305. }
  306. std::string JsonToString(const Json::Value & root)
  307. {
  308. static Json::Value def = []{
  309. Json::Value def;
  310. Json::StreamWriterBuilder::setDefaults(&def);
  311. def["emitUTF8"] = true;
  312. return def;
  313. }();
  314. std::ostringstream stream;
  315. Json::StreamWriterBuilder stream_builder;
  316. stream_builder.settings_ = def;//Config emitUTF8
  317. std::unique_ptr<Json::StreamWriter> writer(stream_builder.newStreamWriter());
  318. writer->write(root, &stream);
  319. return stream.str();
  320. }
  321. int dataCollectionPaperPhysics(int cols, int index, int fontSize, int lineGrayPix, bool engShow,
  322. std::vector<tuple<string, string>>& vecLines, CString dir, std::string& strPngPath, std::string tips) {
  323. /* 这里要做一些栏数 和 vecLines的对应值确认 */
  324. if (2 == cols && 14 * 2 == vecLines.size())
  325. ; // ok
  326. if (3 == cols && 14 * 3 == vecLines.size())
  327. ; // ok
  328. if (4 == cols && 14 * 4 == vecLines.size())
  329. ; // ok
  330. // 生成画布图像
  331. cv::Mat img(cv::Size(1654, 2344), CV_8UC3, cv::Scalar(255, 255, 255));
  332. int ptw = 80; int pth = 40;
  333. cv::Size fSize(0, 0);
  334. int leftPos = 100, rightPos = 1450;
  335. int topPos = 90;
  336. int fontW = rightPos - leftPos + ptw;
  337. vector<cv::Rect> vecPts = {
  338. cv::Rect(100,90,ptw,pth),
  339. cv::Rect(580,90,ptw,pth),
  340. cv::Rect(1450,90,ptw,pth),
  341. cv::Rect(100,2176,ptw,pth),
  342. cv::Rect(1450,2176,ptw,pth),
  343. };
  344. // 画定位点
  345. for (size_t i = 0; i < vecPts.size(); i++)
  346. {
  347. rectangle(img, vecPts[i], cv::Scalar(0, 0, 0), -1);
  348. }
  349. // 画示例框
  350. topPos += pth; topPos += 30;
  351. rectangle(img, cv::Rect(leftPos, topPos, fontW, 200), cv::Scalar(0, 0, 0), 2, 8, 0);
  352. // 画页码框
  353. cv::Rect boxPageNumber(leftPos + fontW - 300, topPos, 300, 200);
  354. rectangle(img, boxPageNumber, cv::Scalar(0, 0, 0), 2, 8, 0);
  355. // 生成二进制码流
  356. /* 二进制码流的坐标在下面函数里面实现,需要用书写获取 */
  357. vector<cv::Rect> vecBoxPages;
  358. createBinString(img, index, ptw, pth, cv::Point(boxPageNumber.x, boxPageNumber.y), vecBoxPages);
  359. string strPageNumInfo = "关联ID: " + to_string(index);
  360. putTextZH(img, fSize, strPageNumInfo.c_str(), cv::Point(boxPageNumber.x + 100, boxPageNumber.y + 50 * 2 + 20 + 15 + 15 + 15), Scalar(0), 20, "宋体");
  361. // 生成page.json
  362. //generatePageJson(vecPts, vecBoxPages);
  363. // 画警示信息
  364. string strMesInfo = "1、请在对应的区域内临摹左侧电路图,每个方框内一个!\
  365. \n\n2、可以使用铅笔和黑色笔绘图。☆\
  366. \n\n3、如果本框内有绘画错误,进行了涂抹修改等操作,请将左上方的填涂框用任意笔进行填涂!☆☆\n";
  367. if (tips.length() > 0)
  368. {
  369. strMesInfo = tips;
  370. }
  371. putTextZH(img, fSize, strMesInfo.c_str(), cv::Point(leftPos + 20, topPos + 20), Scalar(0), 25, "宋体");
  372. int lineTop1 = topPos + 20 + fSize.height + 20;
  373. cv::line(img, cv::Point(leftPos, lineTop1), cv::Point(rightPos + ptw - 300, topPos + 20 + fSize.height + 20), Scalar(0), 2, 8, 0);
  374. // 正确示例
  375. string strEgInfo = "注\n意\n事\n项";
  376. putTextZH(img, fSize, strEgInfo.c_str(), cv::Point(leftPos + 20, topPos + 20 + fSize.height + 20 + 3), Scalar(0), 20, "宋体");
  377. cv::line(img, cv::Point(leftPos + 20 + fSize.width + 10, lineTop1), cv::Point(leftPos + 20 + fSize.width + 10, topPos + 200), Scalar(0, 0, 0), 2, 8, 0);
  378. // 填涂示例
  379. string strtt = "尽量保持手绘内容与示例图相对位置一致!即保持整体相对居中!";
  380. cv::Point ptEgInfo(leftPos + 70, topPos + 20 + fSize.height + 20 + 30);
  381. putTextZH(img, fSize, strtt.c_str(), ptEgInfo, Scalar(0), 20, "宋体");
  382. //cv::Rect rcttbox(ptEgInfo.x + 100, ptEgInfo.y - 5, 30, 30);
  383. //rectangle(img, rcttbox, cv::Scalar(0), -1);
  384. //rcttbox.x += 1;
  385. //rcttbox.y += 1;
  386. //rcttbox.width -= 2;
  387. //rcttbox.height -= 2;
  388. //rectangle(img, rcttbox, cv::Scalar(100, 100, 100), -1);
  389. // 贴图区域
  390. /* 暂不实现 */
  391. topPos += 200;
  392. ///////////////////////////////////////// 主干区域: y 起始坐标:360/////////////////////////////////////////////
  393. Json::Value root(Json::arrayValue);
  394. // +指定像素
  395. auto yhPadding = [&](cv::Rect & rcBox,int pd) {
  396. rcBox.x += pd;
  397. rcBox.y += pd;
  398. rcBox.width -= (pd * 2);
  399. rcBox.height -= (pd * 2);
  400. };
  401. // json valule
  402. auto addValueToJson = [&](Json::Value & root, cv::Rect rcbox, cv::Rect rcNum, cv::Rect rcQues, cv::Rect rcAns,
  403. int iQNum, std::string strTgInfo, std::string strSolution) {
  404. //生成识别信息
  405. Json::Value ttbox;
  406. ttbox["x"] = rcbox.x;
  407. ttbox["y"] = rcbox.y;
  408. ttbox["width"] = rcbox.width;
  409. ttbox["height"] = rcbox.height;
  410. Json::Value queNum;
  411. queNum["x"] = rcNum.x;
  412. queNum["y"] = rcNum.y;
  413. queNum["width"] = rcNum.width;
  414. queNum["height"] = rcNum.height;
  415. Json::Value queInfo;
  416. queInfo["x"] = rcQues.x;
  417. queInfo["y"] = rcQues.y;
  418. queInfo["width"] = rcQues.width;
  419. queInfo["height"] = rcQues.height;
  420. queInfo["info"] = strTgInfo.c_str();
  421. queInfo["solution"] = strSolution.c_str();
  422. Json::Value ansInfo;
  423. ansInfo["x"] = rcAns.x;
  424. ansInfo["y"] = rcAns.y;
  425. ansInfo["width"] = rcAns.width;
  426. ansInfo["height"] = rcAns.height;
  427. Json::Value item;
  428. item["id"] = iQNum;
  429. item["ttbox"] = ttbox;
  430. item["queNum"] = queNum;
  431. item["queInfo"] = queInfo;
  432. item["ansInfo"] = ansInfo;
  433. root.append(item);
  434. };
  435. #if QQM_ADD
  436. topPos += 50; // 间隔预留
  437. int pd = 3;
  438. cv::Size exampleSize(512+ pd *2, 512+ pd *2); // 示例图size
  439. int exdis = 20; // 示例图之间水平方向间隔
  440. int eydis = 50; //
  441. int bigDrawBoxNum = 2;
  442. int smlDrawBoxNum = 2 * 4;
  443. int iQNum = 1;
  444. /*
  445. ---------------------------------------------
  446. | | | |
  447. |示例大图1 |绘画区域1 |绘画区域2 |
  448. | | | |
  449. ---------------------------------------------
  450. | | | |
  451. |示例大图2 |... | |
  452. | | | |
  453. ---------------------------------------------
  454. | |1 |2 |1 |2 |
  455. |示例小图3 |-----------|-----------|
  456. | |3 |4 |3 |4 |
  457. ----------------------------------------------
  458. */
  459. int eleft = max(0, (img.cols - (exampleSize.width + 20) * max_line) / 2);
  460. for (auto ex = 0; ex < max_line; ex++) {
  461. //int _left = eleft + (exampleSize.width + 20)*ex;
  462. // 基础信息准备
  463. int _left = eleft;
  464. int _top = topPos + (exampleSize.height + eydis)*ex;
  465. cv::Rect box(_left, _top, exampleSize.width, exampleSize.height);
  466. rectangle(img, box, cv::Scalar(0), 2, 8, 0);
  467. string strTgInfo = std::get<0>(vecLines[ex]);
  468. string strSolution = std::get<1>(vecLines[ex]);
  469. int _type = atoi(strSolution.c_str()); // 1 big 0 small
  470. // 示例图贴图
  471. cv::Mat _img = cv::imread(strTgInfo, cv::IMREAD_ANYCOLOR);
  472. CV_Assert(!_img.empty());
  473. cv::Mat _rsImg;
  474. if (_type)
  475. _rsImg = paddingResize(_img, exampleSize.width, exampleSize.height);
  476. else {
  477. cv::Mat _rsImg4 = paddingNoResize(_img, exampleSize.width/2, exampleSize.height/2);
  478. _rsImg = cv::Mat(exampleSize, _img.type(), cv::Scalar(255, 255, 255));
  479. _rsImg = splitAndInsertImages(_rsImg4, _rsImg);
  480. cv::line(_rsImg, cv::Point(0, exampleSize.height / 2), cv::Point(exampleSize.width - 1, exampleSize.height / 2), cv::Scalar(0), 1, 8, 0);
  481. cv::line(_rsImg, cv::Point(exampleSize.width / 2, 0), cv::Point(exampleSize.width / 2, exampleSize.height - 1), cv::Scalar(0), 1, 8, 0);
  482. }
  483. cv::Mat _bin;
  484. cv::cvtColor(_rsImg, _bin, cv::COLOR_BGR2GRAY);
  485. cv::threshold(_bin, _bin, 200, 255, THRESH_BINARY);
  486. cv::cvtColor(_bin, _rsImg, cv::COLOR_GRAY2BGR);
  487. _rsImg.copyTo(img(box));
  488. // 绘图区域
  489. int ttW = 20; int ttH = 20; // 填涂框
  490. int __left = _left + box.width + exdis;
  491. int __top = _top;
  492. int __w = exampleSize.width * 2 + exdis;
  493. int __h = exampleSize.height;
  494. if (_type) {
  495. for (auto n = 0; n < bigDrawBoxNum; n++) {
  496. cv::Rect __box(__left+n*(exampleSize.width+exdis), __top, exampleSize.width, exampleSize.height);
  497. cv::rectangle(img, __box, cv::Scalar(0), 2, 8, 0);
  498. // 填涂框子
  499. cv::Rect __ttBox(__box.x, __box.y - ttH, ttW, ttH);
  500. cv::rectangle(img, __ttBox, cv::Scalar(0), 1, 8, 0);
  501. cv::Rect __thBox(__ttBox);
  502. cv::Rect __qBox(__ttBox);
  503. yhPadding(__box, pd);
  504. addValueToJson(root, __ttBox, __ttBox, __ttBox, __box, iQNum++, strTgInfo, strSolution);
  505. }
  506. }
  507. else {
  508. int __col = 4; int __row = 2;
  509. int ___disx = 20;
  510. int ___disy = 20;
  511. int ___w = (__w - ___disx * (__col - 1)) / __col;
  512. int ___h = (__h - ___disy * (__row - 1)) / __row;
  513. for (auto row = 0; row < __row; row++) {
  514. int ___top = __top + row*(___h + ___disy);
  515. for (auto col = 0; col < __col; col++) {
  516. int ___left = __left + col * (___w + ___disx);
  517. cv::Rect ___box(___left, ___top, ___w, ___h);
  518. cv::rectangle(img, ___box, cv::Scalar(0), 2, 8, 0);
  519. // 填涂框子
  520. cv::Rect __ttBox(___box.x, ___box.y - ttH, ttW, ttH);
  521. cv::rectangle(img, __ttBox, cv::Scalar(0), 1, 8, 0);
  522. cv::Rect __thBox(__ttBox);
  523. cv::Rect __qBox(__ttBox);
  524. yhPadding(___box, pd);
  525. addValueToJson(root, __ttBox, __ttBox, __ttBox, ___box, iQNum++, strTgInfo, strSolution);
  526. }
  527. }
  528. }
  529. // fuick
  530. int x = 0;
  531. }
  532. #else
  533. // 文字区域
  534. static int maxLineNum = 14; // 最大行数14
  535. static int ttBoxWidth = 30; // 填涂框的边长
  536. static int tiSl = 10; // 题号和题干间的距离
  537. static int lineDis = 20; // 两行之间的距离
  538. int colWidth = fontW / cols; // 单栏的宽度
  539. fSize.width = 0; fSize.height = 0;
  540. //RNG rng;
  541. for (int col = 0; col < cols; col++)
  542. { // 逐栏画题
  543. int colTopPos = topPos;
  544. int colLeftPos = leftPos + col * colWidth;
  545. for (size_t i = 0; i < maxLineNum; i++)
  546. {
  547. size_t vecIndex = i + col * maxLineNum;
  548. if (vecIndex >= vecLines.size())
  549. {
  550. break;
  551. }
  552. colTopPos += lineDis;
  553. int lineLen = ttBoxWidth + tiSl;
  554. // 画填涂框 30*30 大小
  555. cv::Rect rcbox(colLeftPos, colTopPos, ttBoxWidth, ttBoxWidth);
  556. rectangle(img, rcbox, cv::Scalar(0), 1, 8, 0);
  557. int iQNum = i + 1 + col * maxLineNum;
  558. string strStinfo = to_string(iQNum); strStinfo += ".";
  559. cv::Point ptNum(colLeftPos + ttBoxWidth + tiSl, colTopPos);
  560. putTextZH(img, fSize, strStinfo.c_str(), ptNum, Scalar(0, 0, 0), fontSize, "宋体"); // 跟填涂框保持10px距离
  561. lineLen += fSize.width;
  562. cv::Rect rcNum(ptNum.x, ptNum.y, fSize.width, fSize.height);
  563. strStinfo.clear();
  564. string strTgInfo = std::get<0>(vecLines[vecIndex]);
  565. string strSolution = std::get<1>(vecLines[vecIndex]);
  566. if (!engShow)
  567. ; /* 移除词性 */
  568. //char szTemp[2048];
  569. //memset(szTemp, 0, sizeof(char)*(2048));
  570. //UTF82ANSI(strTgInfo.c_str(), strTgInfo.length(), szTemp, 2048);
  571. //strTgInfo = szTemp;
  572. cv::Point ptQues(colLeftPos + ttBoxWidth + tiSl + fSize.width, colTopPos);
  573. putTextZH(img, fSize, strTgInfo.c_str(), ptQues, Scalar(0, 0, 0), fontSize, "宋体"); // 跟填涂框保持10px距离
  574. lineLen += fSize.width;
  575. cv::Rect rcQues(ptQues.x, ptQues.y, fSize.width, fSize.height);
  576. cv::Rect rcAns(colLeftPos + 30, colTopPos + fSize.height, colWidth - ttBoxWidth, 1);
  577. colTopPos = colTopPos + fSize.height * 3.5; //两行之间两倍的距离用于书写
  578. //lineGrayPix = rng.operator ()(220);
  579. line(img, cv::Point(colLeftPos + 30, colTopPos), cv::Point(colLeftPos + colWidth - 1, colTopPos), Scalar(lineGrayPix, lineGrayPix, lineGrayPix), 1, 8, 0);
  580. rcAns.height = colTopPos - rcAns.y + lineDis;
  581. //生成识别信息
  582. Json::Value ttbox;
  583. ttbox["x"] = rcbox.x;
  584. ttbox["y"] = rcbox.y;
  585. ttbox["width"] = rcbox.width;
  586. ttbox["height"] = rcbox.height;
  587. #if QQM_ADD
  588. cv::rectangle(img, rcbox, cv::Scalar(0, 0, 244), 1, 8, 0);
  589. #endif // QQM_ADD
  590. Json::Value queNum;
  591. queNum["x"] = rcNum.x;
  592. queNum["y"] = rcNum.y;
  593. queNum["width"] = rcNum.width;
  594. queNum["height"] = rcNum.height;
  595. #if QQM_ADD
  596. cv::rectangle(img, rcNum, cv::Scalar(0, 255, 244), 1, 8, 0);
  597. #endif // QQM_ADD
  598. Json::Value queInfo;
  599. queInfo["x"] = rcQues.x;
  600. queInfo["y"] = rcQues.y;
  601. queInfo["width"] = rcQues.width;
  602. queInfo["height"] = rcQues.height;
  603. queInfo["info"] = strTgInfo.c_str();
  604. queInfo["solution"] = strSolution.c_str();
  605. #if QQM_ADD
  606. cv::rectangle(img, rcQues, cv::Scalar(215, 0, 244), 1, 8, 0);
  607. #endif // QQM_ADD
  608. Json::Value ansInfo;
  609. ansInfo["x"] = rcAns.x;
  610. ansInfo["y"] = rcAns.y;
  611. ansInfo["width"] = rcAns.width;
  612. ansInfo["height"] = rcAns.height;
  613. #if QQM_ADD
  614. cv::rectangle(img, rcAns, cv::Scalar(225, 120, 244), 1, 8, 0);
  615. #endif // QQM_ADD
  616. Json::Value item;
  617. item["id"] = iQNum;
  618. item["ttbox"] = ttbox;
  619. item["queNum"] = queNum;
  620. item["queInfo"] = queInfo;
  621. item["ansInfo"] = ansInfo;
  622. root.append(item);
  623. // test
  624. /*rectangle(img, rcbox, cv::Scalar(0, 0, 200), 1, 8, 0);
  625. rectangle(img, rcNum, cv::Scalar(0, 200, 0), 1, 8, 0);
  626. rectangle(img, rcQues, cv::Scalar(100, 0, 0), 1, 8, 0);
  627. rectangle(img, rcAns, cv::Scalar(200, 0, 0), 1, 8, 0);*/
  628. }
  629. }
  630. #endif // QQM_ADD
  631. std::string strJson = JsonToString(root);
  632. CString strTemplatePath;
  633. strTemplatePath.Format(L"%s/json/%d.json", dir, index);
  634. CFile zip;
  635. zip.Open(strTemplatePath, CFile::modeCreate | CFile::modeWrite);
  636. zip.Write((void*)strJson.c_str(), strJson.length());
  637. zip.Close();
  638. wchar_t tempPath[MAX_PATH];
  639. DWORD dwSize = MAX_PATH;
  640. GetTempPath(dwSize, tempPath);//获取临时文件夹路径
  641. static int tmp_index = 1;
  642. wchar_t szPath[MAX_PATH];
  643. _stprintf(szPath, L"%stmp_%d.png", tempPath, tmp_index);
  644. tmp_index++;
  645. if (tmp_index > 10)
  646. {
  647. tmp_index = 1;
  648. }
  649. strPngPath = TstringToGB2312(szPath);
  650. cv::imwrite(strPngPath, img);
  651. /*cv::namedWindow("fuck", 1);
  652. cv::imshow("fuck", img);
  653. cv::waitKey(0);*/
  654. return 0;
  655. }
  656. int dataCollectionPaper(int cols, int index, int fontSize, int lineGrayPix, bool engShow, std::vector<tuple<string, string>>& vecLines, CString dir, std::string& strPngPath, std::string tips) {
  657. /* 这里要做一些栏数 和 vecLines的对应值确认 */
  658. if (2 == cols && 14 * 2 == vecLines.size())
  659. ; // ok
  660. if (3 == cols && 14 * 3 == vecLines.size())
  661. ; // ok
  662. if (4 == cols && 14 * 4 == vecLines.size())
  663. ; // ok
  664. // 生成画布图像
  665. cv::Mat img(cv::Size(1654, 2344), CV_8UC3, cv::Scalar(255, 255, 255));
  666. int ptw = 80; int pth = 40;
  667. cv::Size fSize(0, 0);
  668. int leftPos = 100, rightPos = 1450;
  669. int topPos = 90;
  670. int fontW = rightPos - leftPos + ptw;
  671. vector<cv::Rect> vecPts = {
  672. cv::Rect(100,90,ptw,pth),
  673. cv::Rect(580,90,ptw,pth),
  674. cv::Rect(1450,90,ptw,pth),
  675. cv::Rect(100,2176,ptw,pth),
  676. cv::Rect(1450,2176,ptw,pth),
  677. };
  678. // 画定位点
  679. for (size_t i = 0; i < vecPts.size(); i++)
  680. {
  681. rectangle(img, vecPts[i], cv::Scalar(0, 0, 0), -1);
  682. }
  683. // 画示例框
  684. topPos += pth; topPos += 30;
  685. rectangle(img, cv::Rect(leftPos, topPos, fontW, 200), cv::Scalar(0, 0, 0), 2, 8, 0);
  686. // 画页码框
  687. cv::Rect boxPageNumber(leftPos + fontW - 300, topPos, 300, 200);
  688. rectangle(img, boxPageNumber, cv::Scalar(0, 0, 0), 2, 8, 0);
  689. // 生成二进制码流
  690. /* 二进制码流的坐标在下面函数里面实现,需要用书写获取 */
  691. vector<cv::Rect> vecBoxPages;
  692. createBinString(img, index, ptw, pth, cv::Point(boxPageNumber.x, boxPageNumber.y), vecBoxPages);
  693. string strPageNumInfo = "关联ID: " + to_string(index);
  694. putTextZH(img, fSize, strPageNumInfo.c_str(), cv::Point(boxPageNumber.x + 100, boxPageNumber.y + 50 * 2 + 20 + 15 + 15 + 15), Scalar(0), 20, "宋体");
  695. // 生成page.json
  696. //generatePageJson(vecPts, vecBoxPages);
  697. // 画警示信息
  698. string strMesInfo = "1、请将各题结果书写于横线上,勿写到线下!\
  699. \n\n2、请用黑色笔书写。☆\
  700. \n\n3、如果本题书写有误,进行了涂抹修改等操作,请将题号前矩形框用任意笔进行填涂!☆☆\n";
  701. if (tips.length() > 0)
  702. {
  703. strMesInfo = tips;
  704. }
  705. putTextZH(img, fSize, strMesInfo.c_str(), cv::Point(leftPos + 20, topPos + 20), Scalar(0), 25, "宋体");
  706. int lineTop1 = topPos + 20 + fSize.height + 20;
  707. cv::line(img, cv::Point(leftPos, lineTop1), cv::Point(rightPos + ptw - 300, topPos + 20 + fSize.height + 20), Scalar(0), 2, 8, 0);
  708. // 正确示例
  709. string strEgInfo = "正\n确\n示\n例";
  710. putTextZH(img, fSize, strEgInfo.c_str(), cv::Point(leftPos + 20, topPos + 20 + fSize.height + 20 + 3), Scalar(0), 20, "宋体");
  711. cv::line(img, cv::Point(leftPos + 20 + fSize.width + 10, lineTop1), cv::Point(leftPos + 20 + fSize.width + 10, topPos + 200), Scalar(0, 0, 0), 2, 8, 0);
  712. // 填涂示例
  713. string strtt = "正确填涂";
  714. cv::Point ptEgInfo(leftPos + 70, topPos + 20 + fSize.height + 20 + 30);
  715. putTextZH(img, fSize, strtt.c_str(), ptEgInfo, Scalar(0), 20, "宋体");
  716. cv::Rect rcttbox(ptEgInfo.x + 100, ptEgInfo.y - 5, 30, 30);
  717. rectangle(img, rcttbox, cv::Scalar(0), -1);
  718. rcttbox.x += 1;
  719. rcttbox.y += 1;
  720. rcttbox.width -= 2;
  721. rcttbox.height -= 2;
  722. rectangle(img, rcttbox, cv::Scalar(100, 100, 100), -1);
  723. // 贴图区域
  724. /* 暂不实现 */
  725. topPos += 200;
  726. // 文字区域
  727. static int maxLineNum = 14; // 最大行数14
  728. static int ttBoxWidth = 30; // 填涂框的边长
  729. static int tiSl = 10; // 题号和题干间的距离
  730. static int lineDis = 20; // 两行之间的距离
  731. int colWidth = fontW / cols; // 单栏的宽度
  732. fSize.width = 0; fSize.height = 0;
  733. Json::Value root(Json::arrayValue);
  734. //RNG rng;
  735. for (int col = 0; col < cols; col++)
  736. { // 逐栏画题
  737. int colTopPos = topPos;
  738. int colLeftPos = leftPos + col * colWidth;
  739. for (size_t i = 0; i < maxLineNum; i++)
  740. {
  741. size_t vecIndex = i + col * maxLineNum;
  742. if (vecIndex >= vecLines.size())
  743. {
  744. break;
  745. }
  746. colTopPos += lineDis;
  747. int lineLen = ttBoxWidth + tiSl;
  748. // 画填涂框 30*30 大小
  749. cv::Rect rcbox(colLeftPos, colTopPos, ttBoxWidth, ttBoxWidth);
  750. rectangle(img, rcbox, cv::Scalar(0), 1, 8, 0);
  751. int iQNum = i + 1 + col * maxLineNum;
  752. string strStinfo = to_string(iQNum); strStinfo += ".";
  753. cv::Point ptNum(colLeftPos + ttBoxWidth + tiSl, colTopPos);
  754. putTextZH(img, fSize, strStinfo.c_str(), ptNum, Scalar(0, 0, 0), fontSize, "宋体"); // 跟填涂框保持10px距离
  755. lineLen += fSize.width;
  756. cv::Rect rcNum(ptNum.x, ptNum.y, fSize.width, fSize.height);
  757. strStinfo.clear();
  758. string strTgInfo = std::get<0>(vecLines[vecIndex]);
  759. string strSolution = std::get<1>(vecLines[vecIndex]);
  760. if (!engShow)
  761. ; /* 移除词性 */
  762. //char szTemp[2048];
  763. //memset(szTemp, 0, sizeof(char)*(2048));
  764. //UTF82ANSI(strTgInfo.c_str(), strTgInfo.length(), szTemp, 2048);
  765. //strTgInfo = szTemp;
  766. cv::Point ptQues(colLeftPos + ttBoxWidth + tiSl + fSize.width, colTopPos);
  767. putTextZH(img, fSize, strTgInfo.c_str(), ptQues, Scalar(0, 0, 0), fontSize, "宋体"); // 跟填涂框保持10px距离
  768. lineLen += fSize.width;
  769. cv::Rect rcQues(ptQues.x, ptQues.y, fSize.width, fSize.height);
  770. cv::Rect rcAns(colLeftPos + 30, colTopPos + fSize.height, colWidth - ttBoxWidth, 1);
  771. colTopPos = colTopPos + fSize.height * 3.5; //两行之间两倍的距离用于书写
  772. //lineGrayPix = rng.operator ()(220);
  773. line(img, cv::Point(colLeftPos + 30, colTopPos), cv::Point(colLeftPos + colWidth - 1, colTopPos), Scalar(lineGrayPix, lineGrayPix, lineGrayPix), 1, 8, 0);
  774. rcAns.height = colTopPos - rcAns.y + lineDis;
  775. //生成识别信息
  776. Json::Value ttbox;
  777. ttbox["x"] = rcbox.x;
  778. ttbox["y"] = rcbox.y;
  779. ttbox["width"] = rcbox.width;
  780. ttbox["height"] = rcbox.height;
  781. Json::Value queNum;
  782. queNum["x"] = rcNum.x;
  783. queNum["y"] = rcNum.y;
  784. queNum["width"] = rcNum.width;
  785. queNum["height"] = rcNum.height;
  786. Json::Value queInfo;
  787. queInfo["x"] = rcQues.x;
  788. queInfo["y"] = rcQues.y;
  789. queInfo["width"] = rcQues.width;
  790. queInfo["height"] = rcQues.height;
  791. queInfo["info"] = strTgInfo.c_str();
  792. queInfo["solution"] = strSolution.c_str();
  793. Json::Value ansInfo;
  794. ansInfo["x"] = rcAns.x;
  795. ansInfo["y"] = rcAns.y;
  796. ansInfo["width"] = rcAns.width;
  797. ansInfo["height"] = rcAns.height;
  798. Json::Value item;
  799. item["id"] = iQNum;
  800. item["ttbox"] = ttbox;
  801. item["queNum"] = queNum;
  802. item["queInfo"] = queInfo;
  803. item["ansInfo"] = ansInfo;
  804. root.append(item);
  805. // test
  806. /*rectangle(img, rcbox, cv::Scalar(0, 0, 200), 1, 8, 0);
  807. rectangle(img, rcNum, cv::Scalar(0, 200, 0), 1, 8, 0);
  808. rectangle(img, rcQues, cv::Scalar(100, 0, 0), 1, 8, 0);
  809. rectangle(img, rcAns, cv::Scalar(200, 0, 0), 1, 8, 0);*/
  810. }
  811. }
  812. std::string strJson = JsonToString(root);
  813. CString strTemplatePath;
  814. strTemplatePath.Format(L"%s/json/%d.json", dir, index);
  815. CFile zip;
  816. zip.Open(strTemplatePath, CFile::modeCreate | CFile::modeWrite);
  817. zip.Write((void*)strJson.c_str(), strJson.length());
  818. zip.Close();
  819. wchar_t tempPath[MAX_PATH];
  820. DWORD dwSize = MAX_PATH;
  821. GetTempPath(dwSize, tempPath);//获取临时文件夹路径
  822. static int tmp_index = 1;
  823. wchar_t szPath[MAX_PATH];
  824. _stprintf(szPath, L"%stmp_%d.png", tempPath, tmp_index);
  825. tmp_index++;
  826. if (tmp_index > 10)
  827. {
  828. tmp_index = 1;
  829. }
  830. strPngPath = TstringToGB2312(szPath);
  831. cv::imwrite(strPngPath, img);
  832. /*cv::namedWindow("fuck", 1);
  833. cv::imshow("fuck", img);
  834. cv::waitKey(0);*/
  835. return 0;
  836. }
  837. // rect_label : 模板的切割区域 rect_ocr :检测到的手写区域
  838. double math_iou(cv::Rect rect_label, cv::Rect rect_ocr)
  839. {
  840. int endx = max(rect_label.x + rect_label.width, rect_ocr.x + rect_ocr.width);
  841. int startx = min(rect_label.x, rect_ocr.x);
  842. int width = rect_label.width + rect_ocr.width - (endx - startx);
  843. int endy = max(rect_label.y + rect_label.height, rect_ocr.y + rect_ocr.height);
  844. int starty = min(rect_label.y, rect_ocr.y);
  845. int height = rect_label.height + rect_ocr.height - (endy - starty);
  846. double area = 0.0, iou = 0.0;
  847. if (width <= 0 || height <= 0)
  848. return 0.0;
  849. area = width * height*1.0;
  850. iou = area / double(rect_ocr.area());
  851. return iou;
  852. }
  853. int get_gray_num(cv::Mat & img, cv::Rect & box, int &meanGray, int threshold) {
  854. uchar * ptr;
  855. int count = 0;
  856. long long totalGrayNum = 0;
  857. for (int h = box.y; h < box.y + box.height; h++) {
  858. ptr = img.ptr<uchar>(h);
  859. for (int w = box.x; w < box.x + box.width; w++) {
  860. int pix = static_cast<int>(ptr[w]);
  861. totalGrayNum += pix;
  862. if (pix < threshold)
  863. count++;
  864. }
  865. }
  866. meanGray = totalGrayNum / box.area();
  867. return count;
  868. }
  869. int get_around_box_gray(cv::Mat & img, cv::Rect & box) {
  870. int left = (box.x - box.width / 2) > 0 ? (box.x - box.width / 2) : 0;
  871. int top = (box.y - box.height / 2) > 0 ? (box.y - box.height / 2) : 0;
  872. int right = (box.x + box.width * 3 / 2) < (img.cols - 1) ? (box.x + box.width * 3 / 2) : (img.cols - 1);
  873. int bottom = (box.y + box.height * 3 / 2) < (img.rows - 1) ? (box.y + box.height * 3 / 2) : (img.rows - 1);
  874. uchar * ptr;
  875. std::int64_t total = 0;
  876. int number = 0;
  877. for (int h = top; h < bottom; h++) {
  878. ptr = img.ptr<uchar>(h);
  879. for (int w = left; w < right; w++) {
  880. if (w > box.x && w<(box.x + box.width) && h>box.y&&h < (box.y + box.height))
  881. continue;
  882. total += static_cast<std::int64_t>(ptr[w]);
  883. number++;
  884. }
  885. }
  886. return static_cast<int>(total / number);
  887. }
  888. #define USE_THRESHOLD_VAL 200
  889. bool analysis_ttbox_mark(cv::Mat & imgSrc, cv::Rect & rc) {
  890. int thre = min(200, max(get_around_box_gray(imgSrc, rc), 160));
  891. int gray = get_gray_num(imgSrc, rc, thre, USE_THRESHOLD_VAL);
  892. double ds = gray * 1.0 / rc.area()*1.0;
  893. if (ds > 0.50)
  894. return true;
  895. return false;
  896. }
  897. int cutPaper(int pageNum, std::string strJsonPath, std::string strPaperPath, std::string strSavePath, vector<std::tuple<cv::Rect, std::string>>& vecTranslate)
  898. {
  899. ifstream in(strJsonPath, ios::binary);
  900. if (!in.is_open())
  901. {
  902. return 1;
  903. }
  904. Json::Features features;
  905. Json::Reader reader(features);
  906. Json::Value root;
  907. if (!reader.parse(in, root))
  908. {
  909. return 1;
  910. }
  911. if (!root.isArray())
  912. {
  913. return 1;
  914. }
  915. cv::Mat src = cv::imread(strPaperPath);
  916. if (src.empty())
  917. {
  918. return 1;
  919. }
  920. auto pfGetPos = [](const Json::Value & value, cv::Rect& rc) {
  921. int x = 0, y = 0, w = 0, h = 0;
  922. if (value.isMember("x"))
  923. {
  924. x = value["x"].asInt();
  925. }
  926. if (value.isMember("y"))
  927. {
  928. y = value["y"].asInt();
  929. }
  930. if (value.isMember("width"))
  931. {
  932. w = value["width"].asInt();
  933. }
  934. if (value.isMember("height"))
  935. {
  936. h = value["height"].asInt();
  937. }
  938. rc = cv::Rect(x, y, w, h);
  939. };
  940. for (int i = 0; i < root.size(); i++)
  941. {
  942. Json::Value row = root[i];
  943. std::string id = row["id"].asString();
  944. std::string info = row["queInfo"]["info"].asString();
  945. std::string solution = row["queInfo"]["solution"].asString();
  946. info = ConvertGB2312toUTF8(info.c_str());
  947. solution = ConvertGB2312toUTF8(solution.c_str());
  948. Json::Value ttbox = row["ttbox"];
  949. Json::Value ansInfo = row["ansInfo"];
  950. cv::Rect rc_ttbox;
  951. cv::Rect rc_ansInfo;
  952. pfGetPos(ttbox, rc_ttbox);
  953. pfGetPos(ansInfo, rc_ansInfo);
  954. // 选择框灰度判断
  955. cv::Mat gray_src;
  956. cv::cvtColor(src, gray_src, COLOR_BGR2GRAY);
  957. bool ret = analysis_ttbox_mark(gray_src, rc_ttbox);
  958. char szTxtPath[MAX_PATH] = { 0 };
  959. char szStdPath[MAX_PATH] = { 0 };
  960. char szJpgPath[MAX_PATH] = { 0 };
  961. DWORD dwCount = GetTickCount();
  962. sprintf(szTxtPath, "%s\\%s\\%d_%s_%ld_yy.txt", strSavePath.c_str(), ret ? "abnormal" : "normal", pageNum, id.c_str(), dwCount);
  963. sprintf(szStdPath, "%s\\%s\\%d_%s_%ld_zz.txt", strSavePath.c_str(), ret ? "abnormal" : "normal", pageNum, id.c_str(), dwCount);
  964. sprintf(szJpgPath, "%s\\%s\\%d_%s_%ld.jpg", strSavePath.c_str(), ret ? "abnormal" : "normal", pageNum, id.c_str(), dwCount);
  965. CFile zip1;
  966. zip1.Open(CA2T(szTxtPath), CFile::modeCreate | CFile::modeWrite);
  967. zip1.Write((void*)info.c_str(), info.length());
  968. zip1.Close();
  969. CFile zip2;
  970. zip2.Open(CA2T(szStdPath), CFile::modeCreate | CFile::modeWrite);
  971. zip2.Write((void*)solution.c_str(), solution.length());
  972. zip2.Close();
  973. cv::Mat cut = src(rc_ansInfo);
  974. cv::imwrite(szJpgPath, cut);
  975. int index = 1;
  976. for (auto& iter : vecTranslate)
  977. {
  978. cv::Rect rcOcr = std::get<0>(iter);
  979. std::string words = ConvertGB2312toUTF8(std::get<1>(iter).c_str());
  980. if (math_iou(rc_ansInfo, rcOcr) > 0.5)
  981. {
  982. char szOcrJpgPath[MAX_PATH] = { 0 };
  983. char szOcrJpgText[MAX_PATH] = { 0 };
  984. sprintf(szOcrJpgPath, "%s\\%s\\%d_%s_%ld_%d_%d_%d_%d_%d.jpg", strSavePath.c_str(), ret ? "abnormal_small" : "normal_small", pageNum, id.c_str(), dwCount,
  985. rcOcr.x - rc_ansInfo.x, rcOcr.y - rc_ansInfo.y, rcOcr.width, rcOcr.height, index);
  986. sprintf(szOcrJpgText, "%s\\%s\\%d_%s_%ld_%d_%d_%d_%d_%d.txt", strSavePath.c_str(), ret ? "abnormal_small" : "normal_small", pageNum, id.c_str(), dwCount,
  987. rcOcr.x - rc_ansInfo.x, rcOcr.y - rc_ansInfo.y, rcOcr.width, rcOcr.height, index);
  988. CFile zip3;
  989. zip3.Open(CA2T(szOcrJpgText), CFile::modeCreate | CFile::modeWrite);
  990. zip3.Write((void*)words.c_str(), words.length());
  991. zip3.Close();
  992. cv::Mat cut = src(rcOcr);
  993. cv::imwrite(szOcrJpgPath, cut);
  994. index++;
  995. }
  996. }
  997. }
  998. return 0;
  999. }
  1000. int PareseModeJson(preinfo::templatesInfo& temeplatInfo)
  1001. {
  1002. ifstream in("./page.json", ios::binary);
  1003. if (!in.is_open())
  1004. {
  1005. return 1;
  1006. }
  1007. int uuid = 100000; /// 每个框子的一个独立ID 不会有重复的
  1008. Json::Features features;
  1009. Json::Reader reader(features);
  1010. Json::Value root;
  1011. if (!reader.parse(in, root))
  1012. {
  1013. return 1;
  1014. }
  1015. if (!root.isObject())
  1016. {
  1017. return 1;
  1018. }
  1019. //1.获取模板大小信息
  1020. preinfo::PaperTemplateInfo page;
  1021. Json::Value imageSize = root["imageSize"];
  1022. page.height = imageSize["height"].asInt();
  1023. page.width = imageSize["width"].asInt();
  1024. //2.获取定位点信息
  1025. Json::Value loction = root["location"];
  1026. auto funGetPos = [&](Json::Value item) {
  1027. preinfo::PaperRect<double> pb;
  1028. int x = item["x"].asInt();
  1029. int y = item["y"].asInt();
  1030. int h = item["height"].asInt();
  1031. int w = item["width"].asInt();
  1032. pb.centerx = x + w / 2.0;
  1033. pb.centery = y + h / 2.0;
  1034. pb.width = w;
  1035. pb.height = h;
  1036. return pb;
  1037. };
  1038. double offsetx = page.width; double offsety = page.height;
  1039. for (int i = 0; i < loction.size(); i++)
  1040. {
  1041. Json::Value row = loction[i];
  1042. preinfo::LocationPoint lc;
  1043. lc.id = uuid++;
  1044. auto tm = funGetPos(row);
  1045. lc.centerx = tm.centerx;
  1046. lc.centery = tm.centery;
  1047. lc.width = tm.width;
  1048. lc.height = tm.height;
  1049. if (offsetx > lc.centerx) offsetx = lc.getX();
  1050. if (offsety > lc.centery) offsety = lc.getY();
  1051. page.vecLocaltionPoints.push_back(lc);
  1052. }
  1053. //3.获取客观题信息
  1054. Json::Value pagenumber = root["pagenumber"];
  1055. for (int i = 0; i < pagenumber.size(); i++)
  1056. {
  1057. Json::Value item = pagenumber[i];
  1058. string strId = item["id"].asString();
  1059. preinfo::_QuestionChoice _qstc;
  1060. _qstc.id = uuid++;
  1061. _qstc.vecTiHao.push_back(atoi(strId.c_str()));
  1062. double dBoundBox[4] = { 100000,100000,0,0 };
  1063. _qstc.type = preinfo::BOX_QUESTION_CHOICE_M;
  1064. auto itOpts = item["opt"];
  1065. _qstc.number = itOpts.size();
  1066. std::vector<preinfo::TtItem> _vctOpt;
  1067. for (int i = 0; i < itOpts.size(); i++)
  1068. {
  1069. preinfo::TtItem opt;
  1070. auto tm = funGetPos(itOpts[i]);
  1071. opt.centerx = tm.centerx;
  1072. opt.centery = tm.centery;
  1073. opt.width = tm.width;
  1074. opt.height = tm.height;
  1075. _qstc.itemSize.width = opt.width;
  1076. _qstc.itemSize.height = opt.height;
  1077. dBoundBox[0] = dBoundBox[0] > opt.getX() ? opt.getX() : dBoundBox[0];
  1078. dBoundBox[1] = dBoundBox[1] > opt.getY() ? opt.getY() : dBoundBox[1];
  1079. dBoundBox[2] = dBoundBox[2] < (opt.centerx + opt.width / 2.0) ? (opt.centerx + opt.width / 2.0) : dBoundBox[2];
  1080. dBoundBox[3] = dBoundBox[3] < (opt.centery + opt.height / 2.0) ? (opt.centery + opt.height / 2.0) : dBoundBox[3];
  1081. auto subItem = itOpts[i];
  1082. opt.optName = subItem["optName"].asString();
  1083. _vctOpt.push_back(opt);
  1084. }
  1085. _qstc.width = (dBoundBox[2] - dBoundBox[0]);
  1086. _qstc.height = (dBoundBox[3] - dBoundBox[1]);
  1087. _qstc.centerx = dBoundBox[0] + _qstc.width / 2.0;
  1088. _qstc.centery = dBoundBox[1] + _qstc.height / 2.0;
  1089. _qstc.groups = _vctOpt;
  1090. page._vecQtChoices.push_back(_qstc);
  1091. }
  1092. temeplatInfo.push_back(page);
  1093. return 0;
  1094. }
  1095. int cutPaper(std::string strImagePath, std::string strCurDir, vector<std::tuple<cv::Rect, std::string>>& vecTranslate)
  1096. {
  1097. cv::Mat src = cv::imread(strImagePath);
  1098. if (src.empty())
  1099. {
  1100. return 1;
  1101. }
  1102. int index = 1;
  1103. for (auto& iter : vecTranslate)
  1104. {
  1105. cv::Rect rcOcr = std::get<0>(iter);
  1106. std::string words = ConvertGB2312toUTF8(std::get<1>(iter).c_str());
  1107. DWORD dwCount = GetTickCount();
  1108. time_t tt = std::time(0);
  1109. char szOcrJpgPath[MAX_PATH] = { 0 };
  1110. char szOcrJpgText[MAX_PATH] = { 0 };
  1111. sprintf(szOcrJpgPath, "%s\\%lld_%ld_%d.jpg", strCurDir.c_str(), tt, dwCount, index);
  1112. sprintf(szOcrJpgText, "%s\\%lld_%ld_%d.txt", strCurDir.c_str(), tt, dwCount, index);
  1113. CFile zip3;
  1114. zip3.Open(CA2T(szOcrJpgText), CFile::modeCreate | CFile::modeWrite);
  1115. zip3.Write((void*)words.c_str(), words.length());
  1116. zip3.Close();
  1117. cv::Mat cut = src(rcOcr);
  1118. cv::imwrite(szOcrJpgPath, cut);
  1119. index++;
  1120. }
  1121. return 0;
  1122. }