Browse Source

ocr可以了,遗留一个DPI的问题

zhangyang 6 years ago
parent
commit
523b7f9cf0

BIN
bin/Win32/Debug/zhipuzi_pay_plugin/db/pos.db


File diff suppressed because it is too large
+ 898 - 9937
bin/Win32/Debug/zhipuzi_pay_plugin/log/pos.log


BIN
bin/Win32/Debug/zhipuzi_pay_plugin/skin/aa.bmp


+ 6 - 2
bin/Win32/Debug/zhipuzi_pay_plugin/skin/jinezhuaqu_setting.xml

@@ -101,8 +101,12 @@
 			
 			<HorizontalLayout name="jinezhuaqu_setting_ocr_select_value_search_result_layout" padding="0,10,0.0" height="200">
 				<Label text="预览" width="120" padding="30,0,0,0"/>
-				<HorizontalLayout bkcolor="0xFFF3F3F5" width="220" height="200">
-					<Control bkimage="huodaofukuan.png" padding="20,20,20,20" maxwidth="180" maxheight="160"></Control>
+				<HorizontalLayout bkcolor="0xFFF3F3F5" width="320" height="200">
+					<Control>
+					</Control>
+					<Control name="jinezhuaqu_setting_ocr_select_value_search_result_img"></Control>					
+					<Control>
+					</Control>
 				</HorizontalLayout>
 			</HorizontalLayout>
 		</VerticalLayout>

BIN
bin/Win32/Debug/zhipuzi_pay_plugin/zhipuzi_pay_plugin.exe


BIN
bin/Win32/Debug/zhipuzi_pay_plugin/zpzDll.dll


+ 48 - 18
zhipuzi_pay_plugin/helper/CBitmapHelper.cpp

@@ -85,6 +85,49 @@ int CBitmapHelper::SaveBitmapToFile(HBITMAP  hBitmap, LPCWSTR  lpFileName)   //h
 
 }
 
+HBITMAP CBitmapHelper::Scale(HBITMAP srcBitmap, int MaxWidth, int MaxHeight)
+{
+    BITMAP  Bitmap;
+
+    GetObject(srcBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);
+
+    int srcWidth = Bitmap.bmWidth;
+    int srcHeight = Bitmap.bmHeight;
+
+    double scaleX = (double)srcWidth / MaxWidth;
+    double scaleY = (double)srcHeight / MaxHeight;
+
+    double realScale;
+    if(scaleX > scaleY)
+    {
+        realScale = scaleX;
+    }
+    else
+    {
+        realScale = scaleY;
+    }
+
+    int newWidth = (int)(srcWidth / realScale);
+    int newHeight = (int)(srcHeight / realScale);
+
+    HDC hSrcDC = ::CreateCompatibleDC(NULL);
+    SelectObject(hSrcDC, srcBitmap);
+
+    HDC hMemDC = CreateCompatibleDC(hSrcDC);
+
+    //创建一个与屏幕设备描述表兼容的位图
+    HBITMAP hNewBitmap = CreateCompatibleBitmap(hSrcDC, newWidth, newHeight);
+
+    //把新位图选到内存设备描述表中
+    HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, hNewBitmap);
+
+    ::StretchBlt(hMemDC, 0, 0, newWidth, newHeight, hSrcDC, 0, 0, srcWidth, srcHeight, SRCCOPY);
+
+    hNewBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);
+
+    return hNewBitmap;
+}
+
 HBITMAP CBitmapHelper::CopyScreenToBitmap(LPRECT lpRect)   //lpRect   代表选定区域
 {
     HDC   hScrDC, hMemDC; //屏幕和内存设备描述表
@@ -152,10 +195,10 @@ HBITMAP CBitmapHelper::CopyScreenToBitmap(LPRECT lpRect)   //lpRect   
     DeleteDC(hScrDC);
     DeleteDC(hMemDC);
 
-    return   hBitmap;   //返回位图句柄
+    return hBitmap;   //返回位图句柄
 }
 
-bool CBitmapHelper::OcrRect(LPRECT lpRect, std::string& result)
+bool CBitmapHelper::OcrRect(tesseract::TessBaseAPI& tess, LPRECT lpRect, std::string& result)
 {
     HDC   hScrDC, hMemDC; //屏幕和内存设备描述表
     HBITMAP   hBitmap, hOldBitmap;//位图句柄
@@ -227,30 +270,17 @@ bool CBitmapHelper::OcrRect(LPRECT lpRect, std::string& result)
     //把屏幕设备描述表拷贝到内存设备描述表中
     BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY);
 
-	char* lpmem = new   char[bi.biSizeImage];
+    char* lpmem = new   char[bi.biSizeImage];
 
-	//正向的内存图象数据
-	GetBitmapBits(hBitmap, bi.biSizeImage, lpmem);
+    //正向的内存图象数据
+    GetBitmapBits(hBitmap, bi.biSizeImage, lpmem);
 
     //清除
     DeleteDC(hScrDC);
     DeleteDC(hMemDC);
 
     //开始测试ocr
-    tesseract::TessBaseAPI tess;
-
-    if(tess.Init("./tessdata", "eng"))
-    {
-        std::cout << "OCRTesseract: Could not initialize tesseract." << std::endl;
-        return false;
-    }
-
-    // setup
-    tess.SetPageSegMode(tesseract::PageSegMode::PSM_SINGLE_LINE);
-    tess.SetVariable("save_best_choices", "T");
-
     tess.SetImage((const unsigned char*)lpmem, bm.bmWidth, bm.bmHeight, 4, bm.bmWidthBytes);
-
     tess.Recognize(0);
 
     result = tess.GetUTF8Text();

+ 3 - 1
zhipuzi_pay_plugin/helper/CBitmapHelper.h

@@ -10,8 +10,10 @@ public:
 
 	int SaveBitmapToFile(HBITMAP  hBitmap, LPCWSTR  lpFileName);
 
+	HBITMAP Scale(HBITMAP srcBitmap, int MaxWidth, int MaxHeight);
+
 	HBITMAP CopyScreenToBitmap(LPRECT  lpRect);
 
-	bool OcrRect(LPRECT lpRect, std::string& result);
+	bool OcrRect(tesseract::TessBaseAPI& tess, LPRECT lpRect, std::string& result);
 };
 

+ 25 - 0
zhipuzi_pay_plugin/tool/CSetting.cpp

@@ -347,6 +347,31 @@ void CSetting::Init()
 		m_paramsMap[system_setting_jinezhuaqu_setting_chuangkou_zorder] = "0";
 	}
 
+	//OCR模式的参数
+	std::string system_setting_jinezhuaqu_setting_ocr_left = "system_setting_jinezhuaqu_setting_ocr_left";
+	if (m_paramsMap.find(system_setting_jinezhuaqu_setting_ocr_left) == m_paramsMap.end())
+	{
+		m_paramsMap[system_setting_jinezhuaqu_setting_ocr_left] = "0";
+	}
+
+	std::string system_setting_jinezhuaqu_setting_ocr_top = "system_setting_jinezhuaqu_setting_ocr_top";
+	if (m_paramsMap.find(system_setting_jinezhuaqu_setting_ocr_top) == m_paramsMap.end())
+	{
+		m_paramsMap[system_setting_jinezhuaqu_setting_ocr_top] = "0";
+	}
+
+	std::string system_setting_jinezhuaqu_setting_ocr_right = "system_setting_jinezhuaqu_setting_ocr_right";
+	if (m_paramsMap.find(system_setting_jinezhuaqu_setting_ocr_right) == m_paramsMap.end())
+	{
+		m_paramsMap[system_setting_jinezhuaqu_setting_ocr_right] = "0";
+	}
+
+	std::string system_setting_jinezhuaqu_setting_ocr_bottom = "system_setting_jinezhuaqu_setting_ocr_bottom";
+	if (m_paramsMap.find(system_setting_jinezhuaqu_setting_ocr_bottom) == m_paramsMap.end())
+	{
+		m_paramsMap[system_setting_jinezhuaqu_setting_ocr_bottom] = "0";
+	}
+
     m_mutex.unlock();
 
     //设置好默认参数之后,将默认参数写回到数据库

+ 62 - 6
zhipuzi_pay_plugin/wnd/CSystemSettingWnd.cpp

@@ -230,7 +230,7 @@ LRESULT CSystemSettingWnd::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOO
 	CDialogBuilder builder;
 	CDialogBuilderCallbackEx cb;
 
-	//m_pm.AddPreMessageFilter(this);
+	m_pm.AddPreMessageFilter(this);
 
 	CControlUI* pRoot = builder.Create(_T("system_setting.xml"), (UINT)0, &cb, &m_pm);
 	ASSERT(pRoot && "Failed to parse XML");
@@ -461,6 +461,21 @@ void CSystemSettingWnd::HandleClickMsg(TNotifyUI& msg)
 				}
 			}
 		}
+		else if (m_nType == 4)
+		{
+			if (IsRectEmpty(&m_ocrRect))
+			{
+				MessageBox(m_hWnd, _T("没有设置OCR区域,无法保存"), _T("提示"), MB_OK);
+				return;
+			}
+			else
+			{
+				CSetting::SetParam("system_setting_jinezhuaqu_setting_ocr_left", to_string(m_ocrRect.left).c_str());
+				CSetting::SetParam("system_setting_jinezhuaqu_setting_ocr_top", to_string(m_ocrRect.top).c_str());
+				CSetting::SetParam("system_setting_jinezhuaqu_setting_ocr_right", to_string(m_ocrRect.right).c_str());
+				CSetting::SetParam("system_setting_jinezhuaqu_setting_ocr_bottom", to_string(m_ocrRect.bottom).c_str());
+			}
+		}
 
 		//给监视窗口发个消息
 		m_valueWnd->RestartWatch();
@@ -635,6 +650,7 @@ void CSystemSettingWnd::SetDingweiWnd(std::wstring value, HWND hWnd)
 
 void CSystemSettingWnd::SetOcrWnd(RECT rect)
 {
+	//先把确认的区域保存下来
 	m_ocrRect = rect;
 
 	if (IsRectEmpty(&rect))
@@ -642,17 +658,57 @@ void CSystemSettingWnd::SetOcrWnd(RECT rect)
 		return;
 	}
 
-	//开始识别
+	//开始识别;
 	CBitmapHelper helper;
 	
 	HBITMAP h_bitmap = helper.CopyScreenToBitmap(&m_ocrRect);
 	helper.SaveBitmapToFile(h_bitmap, L"C:\\Users\\zhangyang\\Desktop\\aa.bmp");
 
-	std::string result;
+	//将被截图的进行缩放,用于预览展示
+	HBITMAP h_show_bitmap = helper.Scale(h_bitmap, 320, 200);
+
+	//获得缩放后的图像的信息
+	BITMAP  Bitmap;
+	GetObject(h_show_bitmap, sizeof(BITMAP), (LPSTR)&Bitmap);	
+
+	CControlUI* preview = static_cast<CControlUI*>(m_pm.FindControl(_T("jinezhuaqu_setting_ocr_select_value_search_result_img")));
+
+	//先删除旧的图片
+	std::wstring oldImage = preview->GetBkImage();
+	m_pm.RemoveImage(oldImage.c_str());
+
+	//准备替换新的图片
+	std::srand((unsigned int)time(NULL));
+	std::wstring image_name = to_wstring(std::rand());
+
+	//图片名字一定要每次不一样,不然不会更新
+	std::wstring newImage = _T("jinezhuaqu_setting_ocr_select_value_search_result_img_") + image_name;
+	m_pm.AddImage(newImage.c_str(), h_show_bitmap, Bitmap.bmWidth, Bitmap.bmHeight, false);
 	
-	bool ret = helper.OcrRect(&m_ocrRect, result);
-	if (ret == true)
+	preview->SetBkImage(newImage.c_str());
+	preview->SetFixedWidth(Bitmap.bmWidth);
+	preview->SetFixedHeight(Bitmap.bmHeight);
+
+	std::string ocr_result;
+	
+	bool ret = helper.OcrRect(m_valueWnd->GetTess(), &m_ocrRect, ocr_result);
+
+	DeleteObject(h_bitmap);
+	DeleteObject(h_show_bitmap);
+
+	//更新识别结果
+	CEditUI* ocr_value_edit = static_cast<CEditUI*>(m_pm.FindControl(_T("jinezhuaqu_setting_ocr_select_value")));
+
+	if (!atof(ocr_result.c_str()))
 	{
-		int a = 1;
+		//识别结果不是有效的数字
+		ocr_value_edit->SetText(L"未识别到有效金额");
 	}
+	else
+	{
+		std::string format_value = CLewaimaiString::DoubleToString(atof(ocr_result.c_str()), 2);
+		std::wstring ws_ocr_result = CLewaimaiString::UTF8ToUnicode(format_value);
+		
+		ocr_value_edit->SetText(ws_ocr_result.c_str());
+	}	
 }

+ 87 - 2
zhipuzi_pay_plugin/wnd/CValueWnd.cpp

@@ -5,6 +5,8 @@
 
 #include "../tool/CSerialPort.h"
 
+#include "../helper/CBitmapHelper.h"
+
 void CValueWnd::Notify(TNotifyUI& msg)
 {
     if(msg.sType == _T("click"))
@@ -22,6 +24,9 @@ void CValueWnd::Init()
     //初始化窗口位置
     InitWndPos();
 
+	//抢焦点
+	std::thread(&CValueWnd::TopMostWnd, this).detach();
+
     //添加托盘图标
     AddTrayIcon();
 
@@ -44,6 +49,15 @@ void CValueWnd::Init()
 	pOcrWnd->Create(NULL, _T("智铺子收银插件OCR定位"), UI_WNDSTYLE_FRAME, WS_EX_TOOLWINDOW , 0, 0, 0, 0, NULL);
 	pOcrWnd->ShowWindow(false);
 
+	//OCR的数据初始化
+	if (m_tess.Init("./tessdata", "eng"))
+	{
+		std::cout << "OCRTesseract: Could not initialize tesseract." << std::endl;
+	}
+
+	m_tess.SetPageSegMode(tesseract::PageSegMode::PSM_SINGLE_LINE);
+	m_tess.SetVariable("save_best_choices", "T");
+
     //再安装钩子
     //BOOL ret = InstallHook();
 
@@ -51,6 +65,16 @@ void CValueWnd::Init()
     RestartWatch();
 }
 
+void CValueWnd::TopMostWnd()
+{
+	while (true)
+	{
+		::SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+
+		Sleep(200);
+	}
+}
+
 void CValueWnd::RestartWatch()
 {
 	std::thread(&CValueWnd::StartWatchWork, this).detach();
@@ -64,8 +88,8 @@ void CValueWnd::StartWatchWork()
 	//先暂停已有的监控
 	m_isWatchWork = false;
 
-	//等待1秒,这1秒就是等已有的监控线程自动退出
-	Sleep(1000);
+	//等待2秒,这2秒就是等已有的监控线程自动退出
+	Sleep(2000);
 
 	//然后开始工作
 	m_isWatchWork = true;
@@ -108,6 +132,10 @@ void CValueWnd::StartWatchWork()
 
         std::thread(&CValueWnd::WatchWnd, this).detach();
     }
+	else if (m_nWatchType == 4)
+	{
+		std::thread(&CValueWnd::StartOcrWork, this).detach();
+	}
 }
 
 /*
@@ -229,6 +257,58 @@ void CValueWnd::WatchWnd()
     }
 }
 
+void CValueWnd::StartOcrWork()
+{
+	int system_setting_jinezhuaqu_setting_ocr_left = atoi(CSetting::GetParam("system_setting_jinezhuaqu_setting_ocr_left").c_str());
+	int system_setting_jinezhuaqu_setting_ocr_top = atoi(CSetting::GetParam("system_setting_jinezhuaqu_setting_ocr_top").c_str());
+	int system_setting_jinezhuaqu_setting_ocr_right = atoi(CSetting::GetParam("system_setting_jinezhuaqu_setting_ocr_right").c_str());
+	int system_setting_jinezhuaqu_setting_ocr_bottom = atoi(CSetting::GetParam("system_setting_jinezhuaqu_setting_ocr_bottom").c_str());
+
+	//如果模式变了,或者参数变了,就退出(因为会重新启动一个新的监控)
+	while (m_nWatchType == 4 && m_isWatchWork)
+	{
+		RECT rect;
+		rect.left = system_setting_jinezhuaqu_setting_ocr_left;
+		rect.top = system_setting_jinezhuaqu_setting_ocr_top;
+		rect.right = system_setting_jinezhuaqu_setting_ocr_right;
+		rect.bottom = system_setting_jinezhuaqu_setting_ocr_bottom;
+
+		if (IsRectEmpty(&rect))
+		{
+			
+		}
+		else
+		{
+			CBitmapHelper helper;
+
+			std::string ocr_result;			
+			bool ret = helper.OcrRect(m_tess, &rect, ocr_result);
+
+			if (ret)
+			{
+				if (!atof(ocr_result.c_str()))
+				{
+					//识别结果不是有效的数字
+					CLabelUI* valueLabel = static_cast<CLabelUI*>(m_pm.FindControl(_T("value")));
+
+					valueLabel->SetText(L"0.00");
+				}
+				else
+				{
+					std::string format_value = CLewaimaiString::DoubleToString(atof(ocr_result.c_str()), 2);
+					std::wstring ws_ocr_result = CLewaimaiString::UTF8ToUnicode(format_value);
+
+					CLabelUI* valueLabel = static_cast<CLabelUI*>(m_pm.FindControl(_T("value")));
+
+					valueLabel->SetText(ws_ocr_result.c_str());
+				}
+			}
+		}
+
+		Sleep(200);
+	}
+}
+
 LRESULT CValueWnd::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
 {
     LONG styleValue = ::GetWindowLong(*this, GWL_STYLE);
@@ -827,4 +907,9 @@ void CValueWnd::ConfirmOcrWnd(RECT rect)
 
 	//显示设置窗口
 	m_settingWnd->ShowWindow(true);
+}
+
+tesseract::TessBaseAPI& CValueWnd::GetTess()
+{
+	return m_tess;
 }

+ 8 - 0
zhipuzi_pay_plugin/wnd/CValueWnd.h

@@ -68,6 +68,8 @@ public:
 
 	void Init();
 
+	void TopMostWnd();
+
 	void RestartWatch();
 
 	void StartWatchWork();
@@ -76,6 +78,8 @@ public:
 
 	void WatchWnd();
 
+	void StartOcrWork();
+
 	void StartDingweiWnd();
 	void ConfirmDingweiWnd(std::wstring value, HWND hWnd);
 	void CancalDingweiWnd();
@@ -84,6 +88,8 @@ public:
 
 	void StartOcrWnd();
 	void ConfirmOcrWnd(RECT rect);
+
+	tesseract::TessBaseAPI& GetTess();
 private:
 	void UpdateKexian(const char* data, int length);
 
@@ -122,5 +128,7 @@ private:
 	//OCRģʽµÄ²ÎÊý
 	bool m_is_orc_wnd = false;
 	COcrWnd* pOcrWnd;
+
+	tesseract::TessBaseAPI m_tess;
 };