Browse Source

完成第一期公式数据工具开发

maoyehu 1 year ago
parent
commit
a26b042dc7

+ 8 - 4
Debug/config.ini

@@ -3,15 +3,19 @@ flagWord=1
 FourColScaleParam=16
 ThreeColScaleParam=9
 TwoColScaleParam=6
+Scale=0.4
+WirteHScale=1.8
+LineDis=0.2
+Draw=1
 
 [Set]
-Txt=C:/Users/admin/Desktop/qwqw/1.txt
-Pdf=C:/Users/admin/Desktop/新建文件夹
+Txt=C:/Users/admin/Desktop/3/中文手写公式收集第一批/test.txt
+Pdf=C:/Users/admin/Desktop/3/pdf
 Mode=C:/Users/admin/Desktop/zy-pdf-files/json
 Img=C:/Users/admin/Desktop/zy-pdf-files/dtk
 Cut=C:/Users/admin/Desktop/zy-pdf-files
 Repeat=C:/Users/admin/Desktop/qwqw
 Token=24.086aba1dfaa5d4fdba74f2c62b591b35.2592000.1668825495.282335-21782130
 Csv=D:/qqFileRecv/20221114.csv
-CsvPath=D:/qqFileRecv/20221114.csv
-CsvFileDir=C:/Users/admin/Desktop/qwqw
+CsvPath=C:/Users/admin/Desktop/cut5_6/主观题10万-20221114-5-6.csv
+CsvFileDir=C:/Users/admin/Desktop/cut5_6

+ 12 - 3
MFCApplication1/AssignWords.cpp

@@ -247,11 +247,12 @@ int AssignWordsFromTest(std::string pathName, std::vector<tuple< string, string>
 	CString filepath = csFullPath.Left(nPos);
 	CString FilePath1 = filepath + L"\\config.ini";
 	//CString FilePath2 = filepath + L"\\words.txt";
-	WCHAR wflagWord[10],wFourColScaleParam[10],wThreeColScaleParam[10],wTwoColScaleParam[10];
+	WCHAR wflagWord[10],wFourColScaleParam[10],wThreeColScaleParam[10],wTwoColScaleParam[10],wScale[10];
 	GetPrivateProfileString(L"USER", L"flagWord", L"1", wflagWord, 10, FilePath1);
 	GetPrivateProfileString(L"USER", L"TwoColScaleParam", L"6", wTwoColScaleParam, 10, FilePath1);
 	GetPrivateProfileString(L"USER", L"ThreeColScaleParam", L"9", wThreeColScaleParam, 10, FilePath1);
 	GetPrivateProfileString(L"USER", L"FourColScaleParam", L"16", wFourColScaleParam, 10, FilePath1);
+	GetPrivateProfileString(L"USER", L"Scale", L"1.0", wScale, 10, FilePath1);
 	int nFourColScaleParam = 0, nThreeColScaleParam = 0, nTwoColScaleParam = 0;
 	nFourColScaleParam = _wtoi(wFourColScaleParam);
 	nFourColScaleParam = nFourColScaleParam > 0 ? nFourColScaleParam : 16;
@@ -259,6 +260,8 @@ int AssignWordsFromTest(std::string pathName, std::vector<tuple< string, string>
 	nThreeColScaleParam = nThreeColScaleParam > 0 ? nThreeColScaleParam : 9;
 	nTwoColScaleParam = _wtoi(wTwoColScaleParam);
 	nTwoColScaleParam = nTwoColScaleParam > 0 ? nTwoColScaleParam : 6;
+	double scale = _wtof(wScale);
+
 	CString lpszflagWord(wflagWord);
 	
 	int cout = 0;
@@ -307,8 +310,14 @@ int AssignWordsFromTest(std::string pathName, std::vector<tuple< string, string>
 				return -4;
 			}
 			
-			cv::Size WordsWith = GetTextSize(strTemp.c_str(), font_size, font_family);
-			if (WordsWith.width < maxTwoWith)
+			//cv::Size WordsWith = GetTextSize(strTemp.c_str(), font_size, font_family);
+			cv::Size WordsWith = GetImgSize(strTemp.c_str(), scale);
+			if (WordsWith.width < maxTreeWith)
+			{
+				auto test2 = make_tuple(strTemp, strTempAnother);
+				fourList.push_back(test2);
+			}
+			else if (WordsWith.width < maxTwoWith)
 			{
 				auto test2 = make_tuple(strTemp, strTempAnother);
 				twoList.push_back(test2);

+ 286 - 1
MFCApplication1/CvxText.cpp

@@ -28,6 +28,15 @@ void GetStringSize(HDC hDC, const char* str, int* w, int* h)
 	if (h != 0) *h = size.cy;
 }
 
+cv::Size GetImgSize(const char* strpath, double scale)
+{
+	cv::Mat img = cv::imread(strpath);
+	cv::Size size;
+	size.width = img.cols*scale;
+	size.height = img.rows*scale;
+	return size;
+}
+
 cv::Size GetTextSize(const char* str, int fontSize, const char* fn, bool italic, bool underline)
 {
 	HDC hDC = CreateCompatibleDC(0);
@@ -372,7 +381,283 @@ std::string JsonToString(const Json::Value & root)
 	return stream.str();
 }
 
+int dataCollectionPaperFormula(int cols, int index, int fontSize, int lineGrayPix, bool engShow,
+	std::vector<tuple<string, string>>& vecLines, CString dir, std::string& strPngPath, std::string tips, size_t &icount)
+{
+	/* 这里要做一些栏数 和 vecLines的对应值确认 */
+	if (2 == cols && 14 * 2 == vecLines.size())
+		; // ok 
+	if (3 == cols && 14 * 3 == vecLines.size())
+		; // ok 
+	if (4 == cols && 14 * 4 == vecLines.size())
+		; // ok 
+
+	HMODULE module = GetModuleHandle(0);
+	TCHAR pFileName[MAX_PATH + 2] = { 0 };
+	GetModuleFileName(module, pFileName, MAX_PATH);
+	CString csFullPath(pFileName);
+	int nPos = csFullPath.ReverseFind(_T('\\'));
+	CString filepath = csFullPath.Left(nPos);
+	CString FilePath1 = filepath + L"\\config.ini";
+	WCHAR wScale[10],wh[10],wlineDis[10],wDraw[10];
+	GetPrivateProfileString(L"USER", L"Scale", L"1.0", wScale, 10, FilePath1);
+	GetPrivateProfileString(L"USER", L"WirteHScale", L"1.5", wh, 10, FilePath1);
+	GetPrivateProfileString(L"USER", L"LineDis", L"30", wlineDis, 10, FilePath1);
+	GetPrivateProfileString(L"USER", L"Draw", L"0", wDraw, 10, FilePath1);
+	double scale = _wtof(wScale);
+	double wirteH = _wtof(wh);
+	int mylineDis= _wtof(wlineDis);
+	int drawflag = _wtoi(wDraw);
+
+	// 生成画布图像 
+	cv::Mat img(cv::Size(1654, 2344), CV_8UC3, cv::Scalar(255, 255, 255));
+	int ptw = 80; int pth = 40;
+	cv::Size fSize(0, 0);
+	int leftPos = 100, rightPos = 1450;
+	int topPos = 90;
+	int fontW = rightPos - leftPos + ptw;
+	vector<cv::Rect> vecPts = {
+		cv::Rect(100,90,ptw,pth),
+		cv::Rect(580,90,ptw,pth),
+		cv::Rect(1450,90,ptw,pth),
+		cv::Rect(100,2176,ptw,pth),
+		cv::Rect(1450,2176,ptw,pth),
+	};
+
+
+	// 画定位点
+	for (size_t i = 0; i < vecPts.size(); i++)
+	{
+		rectangle(img, vecPts[i], cv::Scalar(0, 0, 0), -1);
+	}
+
+	// 画示例框
+	topPos += pth; topPos += 30;
+	rectangle(img, cv::Rect(leftPos, topPos, fontW, 200), cv::Scalar(0, 0, 0), 2, 8, 0);
+
+	// 画页码框
+	cv::Rect boxPageNumber(leftPos + fontW - 300, topPos, 300, 200);
+	rectangle(img, boxPageNumber, cv::Scalar(0, 0, 0), 2, 8, 0);
 
+	// 生成二进制码流
+	/* 二进制码流的坐标在下面函数里面实现,需要用书写获取 */
+	vector<cv::Rect> vecBoxPages;
+	createBinString(img, index, ptw, pth, cv::Point(boxPageNumber.x, boxPageNumber.y), vecBoxPages);
+	string strPageNumInfo = "关联ID: " + to_string(index);
+	putTextZH(img, fSize, strPageNumInfo.c_str(), cv::Point(boxPageNumber.x + 100, boxPageNumber.y + 50 * 2 + 20 + 15 + 15 + 15), Scalar(0), 20, "宋体");
+
+	// 生成page.json
+	//generatePageJson(vecPts, vecBoxPages);
+
+	// 画警示信息
+	string strMesInfo = "1、请在对应的区域内临摹左侧电路图,每个方框内一个!\
+						\n\n2、可以使用铅笔和黑色笔绘图。☆\
+						\n\n3、如果本框内有绘画错误,进行了涂抹修改等操作,请将左上方的填涂框用任意笔进行填涂!☆☆\n";
+	if (tips.length() > 0)
+	{
+		strMesInfo = tips;
+	}
+	putTextZH(img, fSize, strMesInfo.c_str(), cv::Point(leftPos + 20, topPos + 20), Scalar(0), 25, "宋体");
+	int lineTop1 = topPos + 20 + fSize.height + 20;
+	cv::line(img, cv::Point(leftPos, lineTop1), cv::Point(rightPos + ptw - 300, topPos + 20 + fSize.height + 20), Scalar(0), 2, 8, 0);
+
+	// 正确示例
+	string strEgInfo = "注\n意\n事\n项";
+	putTextZH(img, fSize, strEgInfo.c_str(), cv::Point(leftPos + 20, topPos + 20 + fSize.height + 20 + 3), Scalar(0), 20, "宋体");
+	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);
+
+	// 填涂示例
+	string strtt = "1、抄写时保持公式的结构与题目内结构相对一致!切勿发生严重变形!\
+		\n\n2、题号 \"n.\"不需要抄写";
+	cv::Point ptEgInfo(leftPos + 70, topPos + 20 + fSize.height + 20 + 15);
+	putTextZH(img, fSize, strtt.c_str(), ptEgInfo, Scalar(0), 20, "宋体");
+
+	//cv::Rect rcttbox(ptEgInfo.x + 100, ptEgInfo.y - 5, 30, 30);
+	//rectangle(img, rcttbox, cv::Scalar(0), -1);
+	//rcttbox.x += 1;
+	//rcttbox.y += 1;
+	//rcttbox.width -= 2;
+	//rcttbox.height -= 2;
+	//rectangle(img, rcttbox, cv::Scalar(100, 100, 100), -1);
+
+
+	// 贴图区域
+	/* 暂不实现 */
+
+	topPos += 200;
+
+
+	///////////////////////////////////////// 主干区域: y 起始坐标:360/////////////////////////////////////////////
+	Json::Value root(Json::arrayValue);
+
+	// +指定像素
+	auto yhPadding = [&](cv::Rect & rcBox, int pd) {
+		rcBox.x += pd;
+		rcBox.y += pd;
+		rcBox.width -= (pd * 2);
+		rcBox.height -= (pd * 2);
+	};
+
+	// json valule
+	auto addValueToJson = [&](Json::Value & root, cv::Rect rcbox, cv::Rect rcNum, cv::Rect rcQues, cv::Rect rcAns,
+		int iQNum, std::string strTgInfo, std::string strSolution) {
+		//生成识别信息
+		Json::Value ttbox;
+		ttbox["x"] = rcbox.x;
+		ttbox["y"] = rcbox.y;
+		ttbox["width"] = rcbox.width;
+		ttbox["height"] = rcbox.height;
+
+		Json::Value queNum;
+		queNum["x"] = rcNum.x;
+		queNum["y"] = rcNum.y;
+		queNum["width"] = rcNum.width;
+		queNum["height"] = rcNum.height;
+
+		Json::Value queInfo;
+		queInfo["x"] = rcQues.x;
+		queInfo["y"] = rcQues.y;
+		queInfo["width"] = rcQues.width;
+		queInfo["height"] = rcQues.height;
+		queInfo["info"] = strTgInfo.c_str();
+		queInfo["solution"] = strSolution.c_str();
+
+		Json::Value ansInfo;
+		ansInfo["x"] = rcAns.x;
+		ansInfo["y"] = rcAns.y;
+		ansInfo["width"] = rcAns.width;
+		ansInfo["height"] = rcAns.height;
+
+		Json::Value item;
+		item["id"] = iQNum;
+		item["ttbox"] = ttbox;
+		item["queNum"] = queNum;
+		item["queInfo"] = queInfo;
+		item["ansInfo"] = ansInfo;
+
+		root.append(item);
+	};
+	static int maxHight = 2140;
+	static int ttBoxWidth = 30;  // 填涂框的边长
+	static int tiSl = 10; // 题号和题干间的距离
+	int lineDis = 30;	// 两行之间的距离
+	int colWidth = fontW / cols; // 单栏的宽度
+	fSize.width = 0; fSize.height = 0;
+	int iQNum = 1;
+
+	//Json::Value root(Json::arrayValue);
+	
+	for (int col = 0; col < cols; col++)
+	{
+		int colTopPos = topPos;
+		int colLeftPos = leftPos + col * colWidth;
+		colTopPos += 20;
+		while (vecLines.size() > icount )
+		{
+			string strTgInfo = std::get<0>(vecLines[icount]);
+			string strSolution = std::get<1>(vecLines[icount]);
+			cv::Mat _img = cv::imread(strTgInfo, cv::IMREAD_ANYCOLOR);
+			//贴图高度计算
+			int h,ih,w;
+			h = _img.rows*scale;// < 30 ? 30 : _img.rows*scale;
+			lineDis = mylineDis;
+			ih = h + h * wirteH + lineDis;
+			if (maxHight < ih + colTopPos)
+				break;
+
+			
+			int lineLen = ttBoxWidth + tiSl;
+			// 画填涂框 30*30 大小
+			cv::Rect rcbox(colLeftPos, colTopPos, ttBoxWidth, ttBoxWidth);
+			rectangle(img, rcbox, cv::Scalar(0), 1, 8, 0);
+			string strStinfo = to_string(iQNum); strStinfo += ".";
+			cv::Point ptNum(colLeftPos + ttBoxWidth + tiSl, colTopPos);
+			putTextZH(img, fSize, strStinfo.c_str(), ptNum, Scalar(0, 0, 0), fontSize, "宋体"); // 跟填涂框保持10px距离
+			lineLen += fSize.width;
+			cv::Rect rcNum(ptNum.x, ptNum.y, fSize.width, fSize.height);
+
+			cv::Point ptQues(colLeftPos + ttBoxWidth + tiSl + fSize.width, colTopPos);
+			cv::Mat sizeimg(cv::Size(_img.cols*scale, _img.rows*scale), CV_32S);
+			cv::resize(_img, sizeimg, cv::Size(_img.cols*scale, _img.rows*scale));
+			cv::Mat bgROIMat = img(Rect(ptQues.x, ptQues.y, _img.cols*scale, _img.rows*scale));
+			sizeimg.copyTo(bgROIMat);
+			if (drawflag != 0)
+				rectangle(img, Rect(ptQues.x, ptQues.y, _img.cols*scale, _img.rows*scale), cv::Scalar(0, 0, 255), 2, 8, 0);
+
+			cv::Rect rcQues(ptQues.x, ptQues.y, fSize.width, fSize.height);
+			cv::Rect rcAns(colLeftPos + 30, colTopPos + h, colWidth - ttBoxWidth, 1);
+
+			colTopPos = colTopPos + h + wirteH *h; //两行之间两倍的距离用于书写
+			//lineGrayPix = rng.operator ()(220);
+			line(img, cv::Point(colLeftPos + 30, colTopPos), cv::Point(colLeftPos + colWidth - 5, colTopPos), Scalar(lineGrayPix, lineGrayPix, lineGrayPix), 1, 8, 0);
+			rcAns.height = colTopPos - rcAns.y + lineDis;
+			colTopPos += lineDis;
+			if(drawflag != 0)
+				rectangle(img, rcAns, cv::Scalar(0, 255, 0), 2, 8, 0);
+
+			//生成识别信息
+			Json::Value ttbox;
+			ttbox["x"] = rcbox.x;
+			ttbox["y"] = rcbox.y;
+			ttbox["width"] = rcbox.width;
+			ttbox["height"] = rcbox.height;
+
+			Json::Value queNum;
+			queNum["x"] = rcNum.x;
+			queNum["y"] = rcNum.y;
+			queNum["width"] = rcNum.width;
+			queNum["height"] = rcNum.height;
+
+			Json::Value queInfo;
+			queInfo["x"] = rcQues.x;
+			queInfo["y"] = rcQues.y;
+			queInfo["width"] = rcQues.width;
+			queInfo["height"] = rcQues.height;
+			queInfo["info"] = strSolution.c_str();
+
+			Json::Value ansInfo;
+			ansInfo["x"] = rcAns.x;
+			ansInfo["y"] = rcAns.y;
+			ansInfo["width"] = rcAns.width;
+			ansInfo["height"] = rcAns.height;
+
+			Json::Value item;
+			item["id"] = iQNum;
+			item["ttbox"] = ttbox;
+			item["queNum"] = queNum;
+			item["queInfo"] = queInfo;
+			item["ansInfo"] = ansInfo;
+			iQNum++;
+			icount++;
+			root.append(item);
+		}
+	}
+	//cv::Mat img = cv::imread(strTgInfo, cv::IMREAD_ANYCOLOR);
+	std::string strJson = JsonToString(root);
+
+	CString strTemplatePath;
+	strTemplatePath.Format(L"%s/json/%d.json", dir, index);
+	CFile zip;
+	zip.Open(strTemplatePath, CFile::modeCreate | CFile::modeWrite);
+	zip.Write((void*)strJson.c_str(), strJson.length());
+	zip.Close();
+
+	wchar_t tempPath[MAX_PATH];
+	DWORD dwSize = MAX_PATH;
+	GetTempPath(dwSize, tempPath);//获取临时文件夹路径
+	static int tmp_index = 1;
+	wchar_t szPath[MAX_PATH];
+	_stprintf(szPath, L"%stmp_%d.png", tempPath, tmp_index);
+	tmp_index++;
+	if (tmp_index > 10)
+	{
+		tmp_index = 1;
+	}
+
+	strPngPath = TstringToGB2312(szPath);
+	cv::imwrite(strPngPath, img);
+	return 0;
+}
 
 int dataCollectionPaperPhysics(int cols, int index, int fontSize, int lineGrayPix, bool engShow,
 	std::vector<tuple<string, string>>& vecLines, CString dir, std::string& strPngPath, std::string tips) {
@@ -442,7 +727,7 @@ int dataCollectionPaperPhysics(int cols, int index, int fontSize, int lineGrayPi
 	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);
 
 	// 填涂示例
-	string strtt = "尽量保持手绘内容与示例图相对位置一致!即保持整体相对居中!";
+	string strtt = "要保持手写结构保持原结构,局部涂抹也算涂抹,需要填涂!!!!题号. 不需要抄写 !!!";
 	cv::Point ptEgInfo(leftPos + 70, topPos + 20 + fSize.height + 20 + 30);
 	putTextZH(img, fSize, strtt.c_str(), ptEgInfo, Scalar(0), 20, "宋体");
 	

+ 4 - 0
MFCApplication1/CvxText.h

@@ -21,6 +21,7 @@ using namespace std;
 
 
 void GetStringSize(HDC hDC, const char* str, int* w, int* h);
+cv::Size GetImgSize(const char* strpath, double scale);
 //获取字符串的宽高
 cv::Size GetTextSize(const char* str, int fontSize, const char *fn = "Arial", bool italic = false, bool underline = false);
 void putTextZH(cv::Mat &dst, cv::Size & rSize, const char* str, cv::Point org, cv::Scalar color, int fontSize,
@@ -60,6 +61,9 @@ int dataCollectionPaper(int cols, int index, int fontSize, int lineGrayPix, bool
 // just for physics
 int dataCollectionPaperPhysics(int cols, int index, int fontSize, int lineGrayPix, bool engShow, std::vector<tuple<string, string>>& vecLines, CString dir, std::string& strPngPath, std::string tips);
 
+int dataCollectionPaperFormula(int cols, int index, int fontSize, int lineGrayPix, bool engShow,
+	std::vector<tuple<string, string>>& vecLines, CString dir, std::string& strPngPath, std::string tips, size_t &icount);
+
 /********************************************************
 	*  @function :  答题卡切割
 	*  @brief    :  brief

+ 26 - 0
MFCApplication1/MFCApplication1Dlg.cpp

@@ -158,6 +158,29 @@ DWORD WINAPI ProcessThread(void *param)
 	
 	auto CovertPdfFunc = [&](std::vector<tuple<string, string>>&  vctFiles, int col, int& pageNum){
 		std::string strPage1;
+		for (size_t i = 0; i < vctFiles.size();)
+		{
+			std::string strPagePath;
+			dataCollectionPaperFormula(col, pageNum, 30, nLineGrayPix, false, vctFiles, pWnd->m_strPdfDir, strPagePath, strTips,i);
+			if (strPage1.length() == 0)
+			{
+				strPage1 = strPagePath;
+			}
+			else
+			{
+				CString strPdfPath;
+				strPdfPath.Format(L"%s/pdf/%d.pdf", pWnd->m_strPdfDir, pageNum);
+				PdfNewFromImage({ strPage1, strPagePath }, TstringToGB2312(strPdfPath.GetBuffer()));
+				strPage1 = "";
+
+				CString strMsg = L"";
+				strMsg.Format(L"%s\r\n", strPdfPath);
+				SendMessage(pWnd->m_hWnd, WM_SHOWINFO, (WPARAM)strMsg.GetBuffer(), 0);
+				strMsg.ReleaseBuffer();
+			}
+			pageNum++;
+		}
+		/*
 		for (size_t i = 0; i < vctFiles.size(); i += max_line * col)
 		{
 			std::vector<tuple<string, string>> vecSmall;
@@ -185,6 +208,7 @@ DWORD WINAPI ProcessThread(void *param)
 			}
 			pageNum++;
 		}
+		*/
 		if (strPage1.length() > 0)
 		{
 			CString strPdfPath;
@@ -208,6 +232,7 @@ DWORD WINAPI ProcessThread(void *param)
 	int maxNum = _wtoi(pWnd->m_strPageNumber);;
 	GetMaxNumFunc(oneList, 1, maxNum);
 	GetMaxNumFunc(twoList, 2, maxNum);
+	GetMaxNumFunc(fourList, 3, maxNum);
 	if (maxNum > 4095)
 	{
 		CString strErrorMsg = L"";
@@ -220,6 +245,7 @@ DWORD WINAPI ProcessThread(void *param)
 	int pageNum = _wtoi(pWnd->m_strPageNumber);
 	CovertPdfFunc(oneList, 1, pageNum);
 	CovertPdfFunc(twoList, 2, pageNum);
+	CovertPdfFunc(fourList, 3, pageNum);
 	
 	//通知发送消息到窗口
 	CString strErrorMsg = L"";

+ 6 - 2
Release/config.ini

@@ -3,10 +3,14 @@ flagWord=1
 FourColScaleParam=16
 ThreeColScaleParam=9
 TwoColScaleParam=6
+Scale=0.4
+WirteHScale=1.8
+LineDis=0.2
+Draw=1
 
 [Set]
-Txt=C:/Users/admin/Desktop/qwqw/1.txt
-Pdf=C:/Users/admin/Desktop/新建文件夹
+Txt=C:/Users/admin/Desktop/3/中文手写公式收集第一批/test.txt
+Pdf=C:/Users/admin/Desktop/3/pdf
 Mode=C:/Users/admin/Desktop/zy-pdf-files/json
 Img=C:/Users/admin/Desktop/zy-pdf-files/dtk
 Cut=C:/Users/admin/Desktop/zy-pdf-files