admin
2022-06-30 a17738e1545ff7dbef6398b8ec1eab93ab59c9a1
ConsoleApplication/THSActionUtil.cpp
@@ -2,6 +2,23 @@
#include "ImgDivider.h"
#include "Win32Util.h"
RecognitionManager* THSActionUtil::recognitionManager;
bool isMainScreen(string str) {
   if (str.find("同花顺(") != string::npos) {
      cout << str << endl;
      if (str.find("副屏") == string::npos) {
         if (str.find("热门股") != string::npos || str.find("我的板块") != string::npos) {
            return true;
         }
      }
   }
   return   false;
}
bool isSecondScreen(string str) {
   return   str.find("同花顺(") != string::npos && str.find("副屏") != string::npos;
}
//获取副屏
HWND getSecondWindow() {
@@ -10,12 +27,59 @@
   for (ele = wlist.begin();ele != wlist.end();ele++) {
      HWND hwnd = *ele;
      string str = Win32Util::getWindowName(hwnd);
      if (str.find("同花顺") != string::npos && str.find("副屏") != string::npos)
      if (isSecondScreen(str))
      {
         return hwnd;
      }
   }
   return 0;
}
HWND THSActionUtil::getL2Win() {
   list<HWND> wlist = Win32Util::searchWindow("同花顺(");
   list<HWND>::iterator ele;
   for (ele = wlist.begin();ele != wlist.end();ele++) {
      HWND hwnd = *ele;
      string str = Win32Util::getWindowName(hwnd);
      if (isMainScreen(str)) {
         return hwnd;
      }
   }
   return 0;
}
bool THSActionUtil::checkEnv() {
   list<HWND> wlist = Win32Util::searchWindow("同花顺(");
   list<HWND>::iterator ele;
   bool fp = false;
   bool zp = false;
   for (ele = wlist.begin();ele != wlist.end();ele++) {
      HWND hwnd = *ele;
      string str = Win32Util::getWindowName(hwnd);
      if (isSecondScreen(str))
      {
         fp = true;
      }
      if (isMainScreen(str)) {
         zp = true;
      }
   }
   if (!zp) {
      throw string("同花顺主屏L2窗口未打开");
   }
   if (!fp) {
      throw string("同花顺副屏没有打开");
   }
   return true;
}
void THSActionUtil::openSecondScreen() {
@@ -29,7 +93,7 @@
   for (ele = wlist.begin();ele != wlist.end();ele++) {
      HWND hwnd = *ele;
      string str = Win32Util::getWindowName(hwnd);
      if (str.find("同花顺") != string::npos && str.find("副屏") != string::npos)
      if (isSecondScreen(str))
      {
         cout << str << endl;
         SetForegroundWindow(hwnd);
@@ -38,7 +102,7 @@
         break;
      }
      if (str.find("同花顺") != string::npos && str.find("热门股") != string::npos) {
      if (isMainScreen(str)) {
         cout << hwnd << endl;
         //获取尺寸
         RECT rc;
@@ -51,6 +115,10 @@
   }
   if (!open) {
      if (mainPage <= 0) {
         throw("未找到首页");
      }
      Win32Util::focus(mainPage);
      //查找主窗口的工具栏
      HWND tool = FindWindowExA(mainPage, NULL, "AfxControlBar100s", NULL);
@@ -72,7 +140,13 @@
   }
}
//添加股票
void THSActionUtil::setGP(std::string quickCode, list<std::string> codeList) {
bool THSActionUtil::setGP(std::string quickCode, list<std::string> codeList) {
   list<std::string> tempCodeList;
   for (std::list<string>::iterator e = codeList.begin();e != codeList.end();e++) {
      tempCodeList.push_back(*e);
   }
   //打开副屏
   HWND sw = getSecondWindow();
   if (sw <= 0)
@@ -84,21 +158,26 @@
   if (sw <= 0) {
      throw("未打开副屏");
   }
   Win32Util::focus(sw);
   //打开板块
   Win32Util::keyboardNum(quickCode);
   Win32Util::keyboardNum(quickCode, 100);
   Win32Util::keyboard(VK_RETURN, 200);
   Sleep(1000);
   Sleep(2000);
   //设置板块中的股票
   //获取板块内容句柄
   HWND content = FindWindowExA(sw, NULL, "AfxFrameOrView100s", NULL);
   cv::Mat img = CaptureUtil::capture(content);
   if (img.cols <= 0 || img.rows <= 0) {
      throw("板块截屏内容为空");
   cv::Mat oimg = CaptureUtil::capture(content);
   cout << "副屏截图:" << oimg.rows << "-" << oimg.cols << endl;
   if (oimg.cols <= 0 || oimg.rows <= 0) {
      throw string("板块截屏内容为空");
   }
   cv::Mat img = ImgUtil::grayImage(oimg);
   oimg.release();
   std::list<GPCodeArea>  areaList = recognitionGPArea(img);
   std::list<string> addList;
@@ -109,7 +188,7 @@
      bool contains = false;
      std::list<string>::iterator e;
      for (e = codeList.begin();e != codeList.end();e++) {
      for (e = tempCodeList.begin();e != tempCodeList.end();e++) {
         if (*e == (*ele).code) {
            contains = true;
            break;
@@ -121,33 +200,70 @@
      }
      else
      {
         codeList.remove((*ele).code);
         tempCodeList.remove((*ele).code);
      }
   
   }
   //-----先删除需要删除的
   //获取内容板块坐标
   RECT rect;
   GetWindowRect(content, &rect);
   
   RECT rect;
   GetWindowRect(sw, &rect);
   Win32Util::mouseMove(rect.left + 10, rect.top + 5, 1);
   Win32Util::click(10);
   for (std::list<GPCodeArea>::iterator ele = delList.begin();ele != delList.end();++ele) {     
      RECT rect;
      GetWindowRect(content, &rect);
      Win32Util::focus(sw);
      int x = rect.left;
      int y = rect.top;
      x += (*ele).startx+5;
      y += (*ele).starty+5;
       //选中删除
      Win32Util::click(x,y,50);
      y += (*ele).starty + 5;      //选中删除
      Win32Util::mouseMove(x, y, 50);
      Win32Util::click(10);
      Win32Util::keyboard(VK_DELETE, 50);
   }
   img.release();
   //----增加
   //截图,识别出增加按钮位置,点击增加,输入内容
   for (std::list<string>::iterator ele = tempCodeList.begin();ele != tempCodeList.end();++ele) {
      addGP(*ele);
      Sleep(100);
   }
   oimg = CaptureUtil::capture(content);
   if (oimg.cols <= 0 || oimg.rows <= 0) {
      throw("板块截屏内容为空");
   }
   img = ImgUtil::grayImage(oimg);
   areaList = recognitionGPArea(img);
   resultList = recognitionNum(img, areaList);
   for (std::list<GPCodeArea>::iterator ele = resultList.begin();ele != resultList.end();++ele) {
      bool contains = false;
      std::list<string>::iterator e;
      for (e = codeList.begin();e != codeList.end();e++) {
         if (*e == (*ele).code) {
            contains = true;
            break;
         }
      }
      if (contains) {
         codeList.remove((*ele).code);
      }
   }
   if (codeList.size() == 0) {
      return true;
   }
   return false;
}
void add(string code) {
void THSActionUtil::addGP(string code) {
   //打开副屏
   HWND sw = getSecondWindow();
   if (sw <= 0)
@@ -161,7 +277,8 @@
   }
   HWND content = FindWindowExA(sw, NULL, "AfxFrameOrView100s", NULL);
   cv::Mat img = CaptureUtil::capture(content);
   cv::Mat oimg = CaptureUtil::capture(content);
   cv::Mat img = ImgUtil::grayImage(oimg);
   if (img.cols <= 0 || img.rows <= 0) {
      throw("板块截屏内容为空");
   }
@@ -169,10 +286,15 @@
   for (std::list<GPCodeArea>::iterator ele = areaList.begin();ele != areaList.end();++ele) {
      GPCodeArea codeArea = *ele;
      if (codeArea.type == IMG_TYPE_ADD) {
         Win32Util::focus(sw);
         RECT rc;
         GetWindowRect(HWND(0x00161728), &rc);
         GetWindowRect(content, &rc);
         int y = rc.top + codeArea.starty + (codeArea.endy - codeArea.starty) / 2;
         int x = rc.left + codeArea.startx + (codeArea.endx - codeArea.startx) / 2;
         Win32Util::click(x, y, 50);
         Sleep(10);
         Win32Util::click(x, y, 50);
         Sleep(10);
         Win32Util::click(x, y, 50);
         //输入股票代码
         Win32Util::keyboardNum(code,1000);
@@ -186,56 +308,9 @@
   }
}
//识别股票代码
std::list<GPCodeArea>  THSActionUtil::recognitionGPArea(cv::Mat img) {
   //获取title分隔线
   int rows = img.rows;
   int cols = img.cols;
   int r;
   int contentStartRow = -1;
   for (r = 5;r < img.rows;r++) {
      if (ImgDivider::isRowFull(img, r, cols - 100, cols - 5, 2)) {
         contentStartRow = r;
      }
list<GPCodeArea> splitGPCodeArea(cv::Mat img, int start_row, int start_col, int end_row, int end_col) {
      if (contentStartRow > -1) {
         break;
      }
   }
   if (contentStartRow < 0) {
      throw("起始行分隔出错");
   }
   //分隔列
   int c = 0;
   int startC = -1;
   int endC = -1;
   for (c = 50;c < cols;c++) {
      if (ImgDivider::isColFull(img, c, contentStartRow + 5, contentStartRow + 100, 2)) {
         if (startC < 0) {
            startC = c;
         }
         else {
            if (c - startC < 20) {
               startC = c;
            }
            else {
               endC = c;
               break;
            }
         }
      }
   }
   if (startC < 0 || endC < 0) {
      throw("内容框分隔出错");
   }
   //cv::imshow("内容", cv::Mat(img, cv::Rect(startC, contentStartRow, endC - startC, rows - contentStartRow)));
   std::list<GPCodeArea> resultList;
   startC += 1;
   endC -= 1;
   list<GPCodeArea> resultList;
   //分隔行内容
   int emptyStartRow = -1;
@@ -244,8 +319,8 @@
   int endf = -1;
   std::list<int*> dataItemList;
   for (int i = contentStartRow + 30;i < rows;i++) {
      bool empty = ImgDivider::isRowEmpty(img, i, startC, startC + 50, 1, 64) && ImgDivider::isRowEmpty(img, i, startC + (endC - startC) / 2 - 40, startC + (endC - startC) / 2 + 40, 1, 64);
   for (int i = start_row;i < end_row;i++) {
      bool empty = ImgDivider::isRowEmpty(img, i, start_col, start_col + 50, 1, _IMG_BINARY_THRESHOLD) && ImgDivider::isRowEmpty(img, i, start_col + (end_col - start_col) / 2 - 40, start_col + (end_col - start_col) / 2 + 40, 1, _IMG_BINARY_THRESHOLD);
      if (empty) {
         if (emptyStartRow < 0) {
            emptyStartRow = i;
@@ -264,9 +339,9 @@
            //内容坐标
               //LogUtil::debug("内容的高度为:%d \n", endf - startf);
            int* dd = (int*)malloc(sizeof(int) * 4);
            *dd = startC;
            *dd = start_col;
            *(dd + 1) = startf;
            *(dd + 2) = endC;
            *(dd + 2) = end_col;
            *(dd + 3) = endf;
            //行数据高大于6才为有效的行高
            if (endf - startf > 6)
@@ -427,6 +502,62 @@
}
//识别股票代码
std::list<GPCodeArea>  THSActionUtil::recognitionGPArea(cv::Mat img) {
   //imwrite("C:\\Users\\Administrator\\Desktop\\ocr\\test.jpg", img);
   //获取title分隔线
   int rows = img.rows;
   int cols = img.cols;
   int r;
   int contentStartRow = -1;
   for (r = 5;r < img.rows;r++) {
      if (ImgDivider::isRowFull(img, r, cols - 100, cols - 5, 2)) {
         contentStartRow = r;
      }
      if (contentStartRow > -1) {
         break;
      }
   }
   if (contentStartRow < 0) {
      throw("起始行分隔出错");
   }
   //分隔列
   int c = 0;
   int startC = -1;
   int endC = -1;
   for (c = 50;c < cols;c++) {
      if (ImgDivider::isColFull(img, c, contentStartRow + 5, contentStartRow + 100, 2)) {
         if (startC < 0) {
            startC = c;
         }
         else {
            if (c - startC < 20) {
               startC = c;
            }
            else {
               endC = c;
               break;
            }
         }
      }
   }
   if (startC < 0 || endC < 0) {
      throw("内容框分隔出错");
   }
   //cv::imshow("内容", cv::Mat(img, cv::Rect(startC, contentStartRow, endC - startC, rows - contentStartRow)));
   startC += 1;
   endC -= 1;
   std::list<GPCodeArea> resultList = splitGPCodeArea(img, contentStartRow + 30, startC, rows, endC);
   return resultList;
}
std::list<GPCodeArea>   THSActionUtil::recognitionNum(cv::Mat img, std::list<GPCodeArea> areaList) {
   if (!recognitionManager) {
@@ -437,11 +568,34 @@
   std::list<GPCodeArea>::iterator ele;
   int index = 0;
   for (ele = areaList.begin();ele != areaList.end();ele++) {
      index++;
      GPCodeArea codeArea = *ele;
      if (codeArea.type == IMG_TYPE_GP) {
         cv::Mat nums = cv::Mat(img, cv::Rect(codeArea.startx, codeArea.starty, codeArea.endx - codeArea.startx + 1, codeArea.endy - codeArea.starty + 1));
         std::list<cv::Mat> list2 = ImgUtil::splitNum(nums);
         //保存分隔的数据
         if (false) {
            string path = "C:\\Users\\Administrator\\Desktop\\ocr\\gpcode\\";
            path.append(to_string(index));
            path.append(".jpg");
            cv::imwrite(path, nums);
         }
         std::list<cv::Mat> list2 = ImgUtil::splitNum(nums, 96);
         if (false) {
            std::list<cv::Mat>::iterator e;
            int ci = 0;
            for (e = list2.begin();e != list2.end();e++) {
               ci++;
               string path = "C:\\Users\\Administrator\\Desktop\\ocr\\gpcode\\";
               path.append(to_string(index)).append("_").append(to_string(ci));
               path.append(".jpg");
               cv::imwrite(path, *e);
            }
         }
         std::list<uchar> resultList = recognitionManager->recognitionGPCode(list2);
         std::list<uchar>::iterator ele1;
         string code = "";
@@ -449,9 +603,231 @@
            code.append(to_string(*ele1));
         }
         codeArea.code = code;
         cout << code << endl;
         codeList.push_back(codeArea);
      }
   }
   return codeList;
}
//分隔L2数据的目录
std::list<GPCodeArea> splitL2Cate(cv::Mat img) {
   int cols = img.cols;
   int contentStartRow = -1;
   int contentEndRow = -1;
   for (int r = 5;r < img.rows;r++) {
      if (ImgDivider::isRowFull(img, r, 10, 200, 2, 10, 30) && ImgDivider::isRowFull(img, r, img.cols - 200, img.cols - 1, 2, 10, 30)) {
         if (contentStartRow < 0)
         {
            contentStartRow = r;
         }
         else {
            if (r - contentStartRow > 10) {
               contentEndRow = r;
            }
         }
      }
      if (contentStartRow > -1 && contentEndRow > -1) {
         break;
      }
   }
   if (contentStartRow < 0 || contentEndRow < 0) {
      throw("起始行或结束行分隔出错");
   }
   //分隔列
   list<int*> dataColIndexs;
   int startf = -1;
   int endf = -1;
   int startIndex = -1;
   for (int i = 10;i < cols;i++) {
      if (startIndex == -1) {
         startIndex = i;
      }
      bool full = ImgDivider::isColFull(img, i, contentStartRow, contentEndRow, 2);
      if (full) {
         if (startf < 0)
         {
            startf = i;
            endf = i;
         }
         else {
            endf = i;
         }
      }
      else {
         if (startf > -1 && endf > -1) {
            int width = endf - startf + 1;
            int* dd = (int*)malloc(sizeof(int) * 2);
            *dd = startIndex;
            *(dd + 1) = startf - 1;
            dataColIndexs.push_back(dd);
            startIndex = i;
         }
         startf = -1;
         endf = -1;
      }
   }
   if (startf > -1 && endf > -1) {
      int width = endf - startf + 1;
      int* dd = (int*)malloc(sizeof(int) * 2);
      *dd = startIndex;
      *(dd + 1) = startf - 1;
      LogUtil::debug("列数据:%d-%d\n", *dd, *(dd + 1));
      dataColIndexs.push_back(dd);
      startf = -1;
      endf = -1;
   }
   if (cols - startIndex > 50) {
      int* dd = (int*)malloc(sizeof(int) * 2);
      *dd = startIndex;
      *(dd + 1) = cols - 1;
      dataColIndexs.push_back(dd);
   }
   std::list<GPCodeArea> areaList;
   list<int*>::iterator ele;
   for (ele = dataColIndexs.begin();ele != dataColIndexs.end();ele++) {
      int* p = *ele;
      int startx = *p;
      int endx = *(p + 1);
      GPCodeArea area = GPCodeArea();
      area.startx = startx;
      area.endx = endx;
      area.starty = contentStartRow;
      area.endy = contentEndRow;
      areaList.push_back(area);
   }
   return areaList;
}
std::map<int,string> THSActionUtil::getListenL2GPCodes() {
   std::list<GPCodeArea> areaList = getListenL2GP();
   std::map<int, string> map;
   for (std::list<GPCodeArea>::iterator ele = areaList.begin();ele != areaList.end();ele++) {
      GPCodeArea data = (*ele);
      if (map.count(data.cateIndex)==0&&data.type== IMG_TYPE_GP) {
         map[data.cateIndex] = data.code;
      }
   }
   return map;
}
std::list<GPCodeArea> THSActionUtil::getListenL2GP() {
   //截图当前有哪些股票代码
   list<HWND> wlist = Win32Util::searchWindow("同花顺(");
   HWND mainPage = 0;
   list<HWND>::iterator ele;
   for (ele = wlist.begin();ele != wlist.end();ele++) {
      HWND hwnd = *ele;
      string str = Win32Util::getWindowName(hwnd);
      if (isMainScreen(str)) {
         cout << hwnd << endl;
         //获取尺寸
         RECT rc;
         GetWindowRect(hwnd, &rc);
         if (rc.right - rc.left > 200 && rc.bottom - rc.top > 200) {
            mainPage = hwnd;
            break;
         }
      }
   }
   if (mainPage <= 0) {
      throw string("L2监听未打开");
   }
   HWND content = FindWindowExA(mainPage, NULL, "AfxFrameOrView100s", NULL);
   //截图
   cv::Mat oimg = CaptureUtil::capture(content);
   cv::Mat img = ImgUtil::grayImage(oimg);
   oimg.release();
   //分隔图片
   std::list<GPCodeArea>  areaList = splitL2Cate(img);
   int index = 0;
   for (std::list<GPCodeArea>::iterator ele = areaList.begin();ele != areaList.end();ele++) {
      GPCodeArea area = *ele;
      index++;
      std::list<GPCodeArea> resultList = splitGPCodeArea(img, area.starty + 20, area.startx, area.endy, area.endx);
      if (false) {
         std::string path = "C:\\Users\\Administrator\\Desktop\\ocr\\gpcode\\";
         path.append(std::to_string(index)).append("_listen.jpg");
         imwrite(path, cv::Mat(img, cv::Rect(area.startx, area.starty, area.endx - area.startx + 1, area.endy - area.starty + 1)));
      }
      for (std::list<GPCodeArea>::iterator ele1 = resultList.begin();ele1 != resultList.end();ele1++) {
         GPCodeArea areaC = *ele1;
         if (areaC.type == IMG_TYPE_GP) {
            list<cv::Mat> nums = ImgUtil::splitNum(cv::Mat(img, cv::Rect(areaC.startx, areaC.starty, areaC.endx - areaC.startx + 1, areaC.endy - areaC.starty + 1)), 96);
            if (!recognitionManager) {
               recognitionManager = new RecognitionManager();
            }
            if (nums.size() != 6) {
               throw string("代码分隔出错");
            }
            list<uchar>  rresult = recognitionManager->recognitionGPCode(nums);
            string num;
            for (std::list<uchar>::iterator e = rresult.begin();e != rresult.end();e++) {
               num.append(to_string(*e));
            }
            (*ele1).code = num;
            (*ele1).cateIndex = index-1;
         }
      }
      return resultList;
   }
}
bool THSActionUtil::setListenL2GP(int p, string code) {
   std::list<GPCodeArea> resultList = getListenL2GP();
   HWND content = FindWindowExA(getL2Win(), NULL, "AfxFrameOrView100s", NULL);
   int index = 0;
   for (std::list<GPCodeArea>::iterator ele = resultList.begin();ele != resultList.end();ele++) {
      GPCodeArea result = *ele;
      if (result.code == code) {
         //点击
         RECT rc;
         GetWindowRect(content, &rc);
         int x = rc.left + result.startx + 5;
         int y = rc.top + result.starty + 5;
         Win32Util::focus(content);
         Win32Util::click(x, y, 50);
         return true;
      }
   }
   return false;
}