| | |
| | | #include "CaptureUtil.h" |
| | | #include "Win32Util.h" |
| | | |
| | | HWND CaptureUtil::level2Frames[8]; |
| | | HWND CaptureUtil::tradeQueueFrames[8]; |
| | |
| | | } |
| | | else { |
| | | |
| | | if (frameInfo.position.bottom - frameInfo.position.top < 100 && frameInfo.position.bottom - frameInfo.position.top >40) |
| | | if (frameInfo.position.bottom - frameInfo.position.top < 200 && frameInfo.position.bottom - frameInfo.position.top >40) |
| | | { |
| | | tempTrade.push_back(frameInfo); |
| | | } |
| | |
| | | using namespace std; |
| | | enum CaptureContentType { |
| | | CAPTURE_TYPE_L2, |
| | | CAPTURE_TYPE_TRADE_QUEUE |
| | | CAPTURE_TYPE_TRADE_QUEUE, |
| | | }; |
| | | struct FrameInfo |
| | | { |
| | |
| | | return TRUE; |
| | | } |
| | | |
| | | //标记1维图像 |
| | | cv::Mat ImgUtil::markMat(cv::Mat mat, cv::Rect rect, uchar borderColor, int borderWidth) { |
| | | for (int r = rect.y; r < rect.y + borderWidth; r++) { |
| | | for (int c = rect.x; c < rect.x + rect.width; c++) { |
| | | mat.ptr<uchar>(r)[c] = borderColor; |
| | | } |
| | | } |
| | | |
| | | for (int r = rect.y + rect.height- borderWidth; r < rect.y + rect.height; r++) { |
| | | for (int c = rect.x; c < rect.x + rect.width; c++) { |
| | | mat.ptr<uchar>(r)[c] = borderColor; |
| | | } |
| | | } |
| | | |
| | | for (int r = rect.y + borderWidth; r < rect.y + rect.height; r++) { |
| | | for (int c = rect.x; c < rect.x + borderWidth; c++) { |
| | | mat.ptr<uchar>(r)[c] = borderColor; |
| | | } |
| | | } |
| | | |
| | | for (int r = rect.y + borderWidth; r < rect.y + rect.height; r++) { |
| | | for (int c = rect.x+rect.width - borderWidth; c < rect.x + rect.width; c++) { |
| | | mat.ptr<uchar>(r)[c] = borderColor; |
| | | } |
| | | } |
| | | |
| | | return mat; |
| | | } |
| | |
| | | int endy; |
| | | }; |
| | | |
| | | struct OCRResult |
| | | { |
| | | string text; |
| | | RECT rect; |
| | | |
| | | }; |
| | | |
| | | |
| | | using namespace std; |
| | | class ImgUtil |
| | | { |
| | |
| | | static cv::Mat formatNumGPCode(cv::Mat num) throw(string); |
| | | |
| | | static cv::Mat formatNumTradeQueue(cv::Mat num) throw(string); |
| | | |
| | | // 标记Mat中的区域 |
| | | static cv::Mat markMat(cv::Mat mat, cv::Rect rect, uchar borderColor, int borderWidth); |
| | | }; |
| | | |
| | | |
| | |
| | | #include "GPUtil.h" |
| | | #include "LogUtil.h" |
| | | #include "L2TradeQueueUtil.h" |
| | | #include "Win32Util.h" |
| | | |
| | | //#define malloc(size) malloc(size) |
| | | //#define free(ptr) free(ptr) |
| | |
| | | void L2DataCapture::_run(int index) |
| | | { |
| | | while (true) { |
| | | |
| | | clock_t origin_start_time = clock(); |
| | | if (killRunnings[index]) |
| | | break; |
| | | TaskChecker::clientLiveTime.l2[index] = clock(); |
| | |
| | | } |
| | | |
| | | if (running && runnings[index] && gpCodes[index].length() > 0) { |
| | | if (index == 0) { |
| | | cout << "-----------------------开始-------------------- " << endl; |
| | | } |
| | | latest_running_times[index] = clock(); |
| | | //识别数据 |
| | | string code = gpCodes[index]; |
| | | try { |
| | | clock_t start = clock(); |
| | | cv::Mat mat = CaptureUtil::capture(index, CAPTURE_TYPE_L2); |
| | | if (mat.cols <= 400 || mat.rows <= 1800) { |
| | | if (mat.cols <= 400 || mat.rows <= 1600) { |
| | | mat.release(); |
| | | mat = NULL; |
| | | Sleep(100); |
| | | throw string("截图出错"); |
| | | } |
| | | if (index == 0) |
| | | { |
| | | cout << "-----------截图时间消耗:--------- " << index << " " << clock() - start << endl; |
| | | } |
| | | |
| | | start = clock(); |
| | | list<TradeData*> resultList = captureLevel2TradeData(mat, index); |
| | | long processTime = clock() - start; |
| | | if (index == 0) |
| | | { |
| | | cout << "-----------识别时间消耗:---------- " << index << " " << clock() - start << endl; |
| | | } |
| | | long processTime = clock() - origin_start_time; |
| | | start = clock(); |
| | | data_callback(index, code, start, processTime, resultList, context); |
| | | cout << "时间消耗:" << processTime << endl; |
| | | if (index == 0) |
| | | { |
| | | cout << "------------数据回调时间消耗:-----------" << clock() - start << endl; |
| | | } |
| | | } |
| | | catch (string st) { |
| | | //delete (openCLExcuter[index]); |
| | |
| | | } |
| | | } |
| | | Sleep(2); |
| | | if (index == 0) |
| | | { |
| | | cout << "-----------整个L2周期时间消耗时间消耗:------------- " << index << " " << clock() - origin_start_time << endl; |
| | | } |
| | | if (index == 0) |
| | | { |
| | | cout << "-----------------------结束-------------------- \n\n " << endl; |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | string code = gpCodes[index]; |
| | | try { |
| | | clock_t start = clock(); |
| | | cv::Mat mat = CaptureUtil::capture(index, CAPTURE_TYPE_TRADE_QUEUE); |
| | | if (mat.cols <= 400 || mat.rows <= 30) { |
| | | mat.release(); |
| | | mat = NULL; |
| | | Sleep(100); |
| | | throw string("截图出错"); |
| | | } |
| | | |
| | | L2TradeQueue result = captureLevel2TradeQueueData(mat, index); |
| | | HWND queueHWND = CaptureUtil::getHWND(index, CAPTURE_TYPE_TRADE_QUEUE); |
| | | L2TradeQueue result = captureLevel2TradeQueueData(queueHWND, index); |
| | | long processTime = clock() - start; |
| | | cout << "时间消耗:" << processTime << endl; |
| | | //cout << "时间消耗:" << processTime << endl; |
| | | trade_queue_data_callback(index, code, result, context); |
| | | } |
| | | catch (...) { |
| | |
| | | } |
| | | Sleep(50); |
| | | } |
| | | } |
| | | |
| | | std::list<string> L2DataCapture::captureLevel2TradeQueueBuyData(OpenCLExcuter* openCLExcuter, cv::Mat& grayImg, int identify) |
| | | { |
| | | if (grayImg.cols == 0 || grayImg.rows == 0) { |
| | | return list<string>(); |
| | | } |
| | | cv::Mat img; |
| | | try { |
| | | list<ImgArea> splitAreas = L2TradeQueueUtil::splitBuyQueue(grayImg, identify); |
| | | int* splitResult = (int*)malloc(sizeof(int) * 4 * splitAreas.size()); |
| | | int index = 0; |
| | | for (list<ImgArea>::iterator ele = splitAreas.begin(); ele != splitAreas.end(); ++ele) { |
| | | ImgArea area = *ele; |
| | | splitResult[index * 4 + 0] = area.startx; |
| | | splitResult[index * 4 + 1] = area.starty; |
| | | splitResult[index * 4 + 2] = area.endx; |
| | | splitResult[index * 4 + 3] = area.endy; |
| | | |
| | | index++; |
| | | } |
| | | |
| | | |
| | | //二值化,方便处理 |
| | | threshold(grayImg, img, _IMG_BINARY_THRESHOLD, 255, cv::THRESH_BINARY); |
| | | |
| | | |
| | | |
| | | clock_t time_2 = clock(); |
| | | unsigned char* zeroData = (unsigned char*)malloc(sizeof(unsigned char) * _NUMBER_GP_CODE_WIDTH * _NUMBER_GP_CODE_HEIGHT); |
| | | for (int r = 0; r < _NUMBER_GP_CODE_HEIGHT; r++) { |
| | | for (int c = 0; c < _NUMBER_GP_CODE_WIDTH; c++) |
| | | { |
| | | zeroData[r * _NUMBER_GP_CODE_WIDTH + c] = ImgUtil::NUMS_GP_CODE[0].data.ptr<uchar>(r)[c]; |
| | | } |
| | | } |
| | | int num_length_per_ele = 5; |
| | | //splitAreasQueue最多12个数字 |
| | | int ele_count_per_line = splitAreas.size(); |
| | | int line_number_count = ele_count_per_line * num_length_per_ele; |
| | | unsigned char* totalNumberData = (unsigned char*)malloc(sizeof(unsigned char) * (_NUMBER_GP_CODE_HEIGHT * 1) * _NUMBER_GP_CODE_WIDTH * 10 * line_number_count); |
| | | unsigned char types[] = { NUM_TYPE_NUM,NUM_TYPE_NUM,NUM_TYPE_NUM,NUM_TYPE_NUM,NUM_TYPE_NUM,NUM_TYPE_NUM,NUM_TYPE_NUM,NUM_TYPE_NUM,NUM_TYPE_NUM,NUM_TYPE_NUM,NUM_TYPE_NUM,NUM_TYPE_NUM,NUM_TYPE_NUM,NUM_TYPE_NUM,NUM_TYPE_NUM,NUM_TYPE_NUM,NUM_TYPE_NUM,NUM_TYPE_NUM }; |
| | | UcharDataInfo typesData = UcharDataInfo(); |
| | | typesData.length = ele_count_per_line; |
| | | typesData.data = types; |
| | | |
| | | openCLExcuter->splitPlateNum(img, IntDataInfo({ splitResult,(int)(ele_count_per_line * 1) }), UcharDataInfo({ totalNumberData, -1 }), typesData, zeroData, _NUMBER_GP_CODE_WIDTH, _NUMBER_GP_CODE_HEIGHT, ele_count_per_line, num_length_per_ele); |
| | | free(splitResult); |
| | | free(zeroData); |
| | | |
| | | //识别 |
| | | uchar* templateNums = (unsigned char*)malloc(sizeof(unsigned char) * (_NUMBER_GP_CODE_HEIGHT * 1) * _NUMBER_GP_CODE_WIDTH * 10 * line_number_count); |
| | | try { |
| | | openCLExcuter->createNumberTemplates(1, _NUMBER_GP_CODE_WIDTH, _NUMBER_GP_CODE_HEIGHT, line_number_count, ImgUtil::numsOneLevel_gpcode, templateNums); |
| | | } |
| | | catch (...) { |
| | | free(totalNumberData); |
| | | free(templateNums); |
| | | throw string("创建数据模板出错"); |
| | | } |
| | | |
| | | |
| | | uchar** numberResult = nullptr; |
| | | //数字识别 |
| | | try { |
| | | numberResult = openCLExcuter->recognition_numbers(totalNumberData, templateNums, 1 * _NUMBER_GP_CODE_HEIGHT, _NUMBER_GP_CODE_WIDTH * 10 * line_number_count, _NUMBER_GP_CODE_WIDTH, _NUMBER_GP_CODE_HEIGHT, line_number_count); |
| | | //释放内存 |
| | | free(totalNumberData); |
| | | free(templateNums); |
| | | } |
| | | catch (...) { |
| | | //释放内存 |
| | | free(totalNumberData); |
| | | free(templateNums); |
| | | throw string("数字识别出错"); |
| | | } |
| | | |
| | | img.release(); |
| | | |
| | | //循环读取数字 |
| | | uchar* lineData = numberResult[0]; |
| | | list<string> buyQueueList; |
| | | for (int i = 0; i < ele_count_per_line; i++) { |
| | | string num = ""; |
| | | for (int j = 0; j < num_length_per_ele; j++) { |
| | | num.append(to_string(lineData[num_length_per_ele * i + j])); |
| | | } |
| | | buyQueueList.push_back(num); |
| | | } |
| | | |
| | | //释放内存 |
| | | free(lineData); |
| | | index++; |
| | | free(numberResult); |
| | | return buyQueueList; |
| | | } |
| | | catch (...) { |
| | | img.release(); |
| | | img = NULL; |
| | | throw int(ERROR_CODE_DIVIDE_IMG_FAIL); |
| | | } |
| | | } |
| | | |
| | | cv::Mat L2DataCapture::grayImg(OpenCLExcuter* openCLExcuter, cv::Mat& oimg) |
| | | { |
| | | cv::Mat img = cv::Mat::zeros(oimg.rows, oimg.cols, CV_8UC1); |
| | | |
| | | if (oimg.channels() == 1) { |
| | | //黑白图片 |
| | | img.data = oimg.data; |
| | | } |
| | | else { |
| | | try { |
| | | if (oimg.channels() == 3) |
| | | { |
| | | openCLExcuter->rgb2Gray(oimg, img.data); |
| | | } |
| | | else { |
| | | openCLExcuter->rgba2Gray(oimg, img.data); |
| | | } |
| | | oimg.release(); |
| | | } |
| | | catch (...) { |
| | | oimg.release(); |
| | | oimg = NULL; |
| | | img.release(); |
| | | img = NULL; |
| | | throw string("灰度出错"); |
| | | } |
| | | } |
| | | |
| | | return img; |
| | | } |
| | | |
| | | void L2DataCapture::setGPCode(int index, string code) { |
| | |
| | | { |
| | | openCLExcuter[i] = new OpenCLExcuter(); |
| | | openCLExcuter[i]->init(); |
| | | openCLExcuterQueue[i]= new OpenCLExcuter(); |
| | | openCLExcuterQueue[i] = new OpenCLExcuter(); |
| | | openCLExcuterQueue[i]->init(); |
| | | |
| | | tradeQueueCapture[i] = new TradeQueueCapture(); |
| | |
| | | |
| | | list<TradeData*> resultList = captureLevel2TradeData(openCLExcuter[identify], oimg, identify); |
| | | |
| | | std::cout << "-------L2行情识别结束任务: threadid-" << std::this_thread::get_id() << " 序号:" << identify << " CODE:" << gpCodes[identify] << " 耗时:" << clock() - starttime << " 数据量:" << resultList.size() << endl; |
| | | //std::cout << "-------L2行情识别结束任务: threadid-" << std::this_thread::get_id() << " 序号:" << identify << " CODE:" << gpCodes[identify] << " 耗时:" << clock() - starttime << " 数据量:" << resultList.size() << endl; |
| | | |
| | | return resultList; |
| | | } |
| | |
| | | |
| | | list<TradeData*> L2DataCapture::captureLevel2TradeData(OpenCLExcuter* openCLExcuter, cv::Mat& oimg, int identify) |
| | | { |
| | | bool ENABLE_LOG = FALSE; |
| | | |
| | | if (oimg.cols <= 0 || oimg.rows <= 0) { |
| | | throw string("图像数据错误"); |
| | |
| | | } |
| | | //img.data = imgData; |
| | | clock_t time_2_ = clock(); |
| | | if (identify == 0) |
| | | if (identify == 0&& ENABLE_LOG) |
| | | { |
| | | std::cout << "灰度完成: threadid-" << std::this_thread::get_id() << " 耗时:" << (time_2_ - time_1) << " 截图尺寸:" << img.cols << "x" << img.rows << endl; |
| | | |
| | |
| | | |
| | | clock_t time_3 = clock(); |
| | | //LogUtil::debug("分隔完成"); |
| | | if (identify == 0) |
| | | if (identify == 0 && ENABLE_LOG) |
| | | std::cout << "分隔完成: threadid-" << std::this_thread::get_id() << " 耗时:" << time_3 - time_2 << "总耗时:" << time_3 - time_1 << endl; |
| | | |
| | | //结果初始化 |
| | | list<TradeData*> resultList; |
| | | for (int i = 0; i < rowDataList.size(); i++) { |
| | | TradeData *td = new TradeData; |
| | | TradeData* td = new TradeData; |
| | | resultList.push_back(td); |
| | | } |
| | | |
| | |
| | | free(notNumberResult); |
| | | |
| | | clock_t time_5 = clock(); |
| | | if (identify == 0) |
| | | if (identify == 0 && ENABLE_LOG) |
| | | std::cout << "非数字数据识别完成: threadid-" << std::this_thread::get_id() << " 耗时:" << time_5 - time_3 << "总耗时:" << time_5 - time_1 << endl; |
| | | |
| | | |
| | |
| | | |
| | | unsigned char* totalNumberData = (unsigned char*)malloc(sizeof(unsigned char) * (_NUMBER_L2_HEIGHT * rowDataList.size()) * _NUMBER_L2_WIDTH * 10 * _NUMBER_L2_TOTAL_NUMBER); |
| | | clock_t time_31 = clock(); |
| | | if (identify == 0) |
| | | if (identify == 0 && ENABLE_LOG) |
| | | std::cout << "数据准备-图像数据准备: threadid-" << std::this_thread::get_id() << " 耗时:" << time_31 - time_3 << "总耗时:" << time_31 - time_1 << endl; |
| | | |
| | | int* pos = (int*)malloc(sizeof(int) * 4 * 4 * rowDataList.size()); |
| | |
| | | |
| | | |
| | | clock_t time_32 = clock(); |
| | | if (identify == 0) |
| | | if (identify == 0 && ENABLE_LOG) |
| | | std::cout << "数据准备-位置数据准备: threadid-" << std::this_thread::get_id() << " 耗时:" << time_32 - time_31 << "总耗时:" << time_32 - time_1 << endl; |
| | | |
| | | unsigned char* zeroData = (unsigned char*)malloc(sizeof(unsigned char) * _NUMBER_L2_WIDTH * _NUMBER_L2_HEIGHT); |
| | |
| | | } |
| | | |
| | | clock_t time_33 = clock(); |
| | | if (identify == 0) |
| | | if (identify == 0 && ENABLE_LOG) |
| | | std::cout << "数据准备-0数据准备: threadid-" << std::this_thread::get_id() << " 耗时:" << time_33 - time_32 << "总耗时:" << time_33 - time_1 << endl; |
| | | try { |
| | | openCLExcuter->splitL2Num(img.data, img.cols, img.rows, pos, 4 * rowDataList.size(), zeroData, _NUMBER_L2_WIDTH, _NUMBER_L2_HEIGHT, _NUMBER_L2_TOTAL_NUMBER, totalNumberData); |
| | |
| | | |
| | | */ |
| | | clock_t time_34 = clock(); |
| | | if (identify == 0) |
| | | if (identify == 0 && ENABLE_LOG) |
| | | std::cout << "数据准备-数字分隔完成: threadid-" << std::this_thread::get_id() << " 耗时:" << time_34 - time_33 << "总耗时:" << time_34 - time_1 << endl; |
| | | |
| | | //准备模板数字 |
| | |
| | | |
| | | //ImgUtil::createTemplateNumData(data.size()); |
| | | clock_t time_4 = clock(); |
| | | if (identify == 0) |
| | | if (identify == 0 && ENABLE_LOG) |
| | | std::cout << "数据准备-模板数字准备完成: threadid-" << std::this_thread::get_id() << " 耗时:" << time_4 - time_34 << "总耗时:" << time_4 - time_1 << endl; |
| | | |
| | | |
| | | if (identify == 0) |
| | | if (identify == 0 && ENABLE_LOG) |
| | | std::cout << "数据准备完成: threadid-" << std::this_thread::get_id() << " 耗时:" << time_4 - time_3 << "总耗时:" << time_4 - time_1 << endl; |
| | | |
| | | |
| | |
| | | |
| | | clock_t time_6 = clock(); |
| | | //LogUtil::debug("识别完成"); |
| | | if (identify == 0) |
| | | if (identify == 0 && ENABLE_LOG) |
| | | std::cout << "数字识别完成: threadid-" << std::this_thread::get_id() << " 耗时:" << time_6 - time_5 << "总耗时:" << time_6 - time_1 << endl; |
| | | |
| | | //释放内存 |
| | | img.release(); |
| | | rowDataList.clear(); |
| | | list<int*>().swap(rowDataList); |
| | | |
| | | |
| | | return resultList; |
| | | } |
| | | |
| | | L2TradeQueue L2DataCapture::captureLevel2TradeQueueData(HWND hwnd, int index) |
| | | { |
| | | cv::Mat mat = CaptureUtil::capture(hwnd); |
| | | return captureLevel2TradeQueueData(mat,index); |
| | | HWND buyQueueHWND = L2TradeQueueUtil::getTradeQueueBuyHWND(hwnd); |
| | | //获取位置 |
| | | RECT prect; |
| | | Win32Util::getWindowRect(hwnd, &prect); |
| | | RECT buyRect; |
| | | Win32Util::getWindowRect(buyQueueHWND, &buyRect); |
| | | cv::Mat mat = CaptureUtil::capture(hwnd); |
| | | if (mat.cols <= 400 || mat.rows <= 30) { |
| | | mat.release(); |
| | | mat = NULL; |
| | | Sleep(100); |
| | | throw string("截图出错"); |
| | | } |
| | | cv::Rect rect = cv::Rect(buyRect.left - prect.left, buyRect.top - prect.top, buyRect.right - buyRect.left + 1, buyRect.bottom - buyRect.top + 1); |
| | | return captureLevel2TradeQueueData(mat, rect, index); |
| | | } |
| | | |
| | | L2TradeQueue L2DataCapture::captureLevel2TradeQueueData(cv::Mat& oimg, int identify) |
| | | L2TradeQueue L2DataCapture::captureLevel2TradeQueueData(cv::Mat& oimg, cv::Rect buyQueueArea, int identify) |
| | | { |
| | | return captureLevel2TradeQueueData(openCLExcuterQueue[identify],oimg,identify); |
| | | return captureLevel2TradeQueueData(openCLExcuterQueue[identify], oimg, buyQueueArea, identify); |
| | | } |
| | | |
| | | L2TradeQueue L2DataCapture::captureLevel2TradeQueueData(OpenCLExcuter* openCLExcuter, cv::Mat& oimg, int identify) |
| | | L2TradeQueue L2DataCapture::captureLevel2TradeQueueData(OpenCLExcuter* openCLExcuter, cv::Mat& oimg, cv::Rect buyQueueArea, int identify) |
| | | { |
| | | cv::Mat img = cv::Mat::zeros(oimg.rows, oimg.cols, CV_8UC1); |
| | | |
| | | if (oimg.channels() == 1) { |
| | | //黑白图片 |
| | | img.data = oimg.data; |
| | | } |
| | | else { |
| | | try { |
| | | if (oimg.channels() == 3) |
| | | { |
| | | openCLExcuter->rgb2Gray(oimg, img.data); |
| | | } |
| | | else { |
| | | openCLExcuter->rgba2Gray(oimg, img.data); |
| | | } |
| | | oimg.release(); |
| | | } |
| | | catch (...) { |
| | | oimg.release(); |
| | | oimg = NULL; |
| | | img.release(); |
| | | img = NULL; |
| | | throw string("灰度出错"); |
| | | cv::Mat img = grayImg(openCLExcuter, oimg); |
| | | cv::Mat tmpImg = cv::Mat(img, buyQueueArea); |
| | | cv::Mat buyQueueImg = cv::Mat::zeros(buyQueueArea.height, buyQueueArea.width, CV_8UC1); |
| | | uchar* datas = (uchar*)malloc(sizeof(uchar)* buyQueueArea.height* buyQueueArea.width); |
| | | for (int r = 0; r < buyQueueImg.rows; r++) { |
| | | for (int c = 0; c < buyQueueImg.cols; c++) { |
| | | datas[r * buyQueueImg.cols + c] = tmpImg.ptr<uchar>(r)[c]; |
| | | } |
| | | } |
| | | buyQueueImg.data = datas; |
| | | |
| | | |
| | | //过滤黄底白字 |
| | | L2TradeQueueUtil::filterTradeQueueBuyMat(buyQueueImg); |
| | | if (FALSE) |
| | | { |
| | | string path = string("C:\\Users\\Administrator\\Desktop\\ocr\\trade_queue\\origin\\").append(to_string(identify)).append("_").append(to_string(rand()).append(".png")); |
| | | cv::imwrite(path, buyQueueImg); |
| | | } |
| | | L2TradeQueue tradeQueue = captureLevel2TradeQueueViewData(openCLExcuter, img, identify); |
| | | try { |
| | | list<ImgArea> splitAreas = L2TradeQueueUtil::splitElements(img); |
| | | int* splitResult = (int*)malloc(sizeof(int) * 4 * 6); |
| | | std::list<string> buyQueueList = captureLevel2TradeQueueBuyData(openCLExcuter, buyQueueImg, identify); |
| | | tradeQueue.buyQueue = buyQueueList; |
| | | } |
| | | catch (...) { |
| | | |
| | | } |
| | | free(datas); |
| | | return tradeQueue; |
| | | } |
| | | |
| | | L2TradeQueue L2DataCapture::captureLevel2TradeQueueViewData(OpenCLExcuter* openCLExcuter, cv::Mat& img, int identify) |
| | | { |
| | | L2TradeQueue tradeQueue; |
| | | try { |
| | | list<ImgArea> splitAreas = L2TradeQueueUtil::splitViewElements(img); |
| | | int* splitResult = (int*)malloc(sizeof(int) * 4 * splitAreas.size()); |
| | | int index = 0; |
| | | for (list<ImgArea>::iterator ele = splitAreas.begin(); ele != splitAreas.end(); ++ele) { |
| | | ImgArea area = *ele; |
| | |
| | | } |
| | | } |
| | | int num_length_per_ele = 7; |
| | | //splitAreasQueue最多8个数字 |
| | | int ele_count_per_line = 6; |
| | | int line_number_count = ele_count_per_line * num_length_per_ele; |
| | | unsigned char* totalNumberData = (unsigned char*)malloc(sizeof(unsigned char) * (_NUMBER_GP_CODE_HEIGHT * 1) * _NUMBER_GP_CODE_WIDTH * 10 * line_number_count); |
| | | unsigned char types[] = { NUM_TYPE_TIME,NUM_TYPE_TIME,NUM_TYPE_PRICE, NUM_TYPE_NUM_SHOU,NUM_TYPE_PRICE, NUM_TYPE_NUM_SHOU }; |
| | | unsigned char types[] = { NUM_TYPE_TIME,NUM_TYPE_TIME,NUM_TYPE_PRICE, NUM_TYPE_NUM_SHOU,NUM_TYPE_PRICE, NUM_TYPE_NUM_SHOU,NUM_TYPE_NUM,NUM_TYPE_NUM }; |
| | | UcharDataInfo typesData = UcharDataInfo(); |
| | | typesData.length = 6; |
| | | typesData.length = ele_count_per_line; |
| | | typesData.data = types; |
| | | |
| | | openCLExcuter->splitPlateNum(img, IntDataInfo({ splitResult,(int)(ele_count_per_line * 1) }), UcharDataInfo({ totalNumberData, -1 }), typesData, zeroData, _NUMBER_GP_CODE_WIDTH, _NUMBER_GP_CODE_HEIGHT, ele_count_per_line, num_length_per_ele); |
| | |
| | | sellOneTime.append(to_string(lineData[5])).append(to_string(lineData[6])); |
| | | |
| | | string buyOneTime = ""; |
| | | buyOneTime.append(to_string(lineData[num_length_per_ele*1+1])).append(to_string(lineData[num_length_per_ele * 1 + 2])); |
| | | buyOneTime.append(to_string(lineData[num_length_per_ele * 1 + 1])).append(to_string(lineData[num_length_per_ele * 1 + 2])); |
| | | buyOneTime.append(":"); |
| | | buyOneTime.append(to_string(lineData[num_length_per_ele * 1 + 3])).append(to_string(lineData[num_length_per_ele * 1 + 4])); |
| | | buyOneTime.append(":"); |
| | |
| | | free(lineData); |
| | | index++; |
| | | free(numberResult); |
| | | |
| | | |
| | | L2TradeQueue tradeQueue = L2TradeQueue(); |
| | | |
| | | tradeQueue = L2TradeQueue(); |
| | | tradeQueue.buyOnePrice = buyOnePrice; |
| | | tradeQueue.buyOneVolumn = buyOneNum; |
| | | tradeQueue.buyTime = buyOneTime; |
| | |
| | | img = NULL; |
| | | throw int(ERROR_CODE_DIVIDE_IMG_FAIL); |
| | | } |
| | | |
| | | } |
| | | |
| | | //捕获level2的盘口数据 |
| | |
| | | string buyTime; |
| | | string buyOnePrice; |
| | | string buyOneVolumn; |
| | | //成交队列 |
| | | list<string> buyQueue; |
| | | }; |
| | | |
| | | typedef void (*CallbackFun)(int index, string code,long captureTime,long processTime, list<TradeData*> dataList, void* contex); |
| | |
| | | |
| | | static void _run_trade_queue(int index); |
| | | |
| | | //识别买入队列 |
| | | static std::list<string> captureLevel2TradeQueueBuyData(OpenCLExcuter* openCLExcuter, cv::Mat& grayImg,int identify); |
| | | |
| | | //灰度图像 |
| | | static cv::Mat grayImg(OpenCLExcuter* openCLExcuter, cv::Mat& oImg); |
| | | |
| | | |
| | | public: |
| | |
| | | |
| | | //捕获level2的盘口数据 |
| | | static list<TradeData*> captureLevel2TradeData(HWND hwnd,int index) throw(int); |
| | | static list<TradeData*> captureLevel2TradeData(cv::Mat& oimg,int identify); |
| | | static list<TradeData*> captureLevel2TradeData(cv::Mat& oimg, int identify); |
| | | static list<TradeData*> captureLevel2TradeData(OpenCLExcuter *openCLExcuter, cv::Mat& oimg, int identify); |
| | | |
| | | |
| | | static L2TradeQueue captureLevel2TradeQueueData(HWND hwnd, int index); |
| | | static L2TradeQueue captureLevel2TradeQueueData(cv::Mat& oimg, int identify); |
| | | static L2TradeQueue captureLevel2TradeQueueData(OpenCLExcuter* openCLExcuter, cv::Mat& oimg, int identify); |
| | | |
| | | static L2TradeQueue captureLevel2TradeQueueData(cv::Mat& oimg, cv::Rect buyQueueArea, int identify); |
| | | static L2TradeQueue captureLevel2TradeQueueData(OpenCLExcuter* openCLExcuter, cv::Mat& oimg, cv::Rect buyQueueArea, int identify); |
| | | // 买卖队列概要信息识别 |
| | | static L2TradeQueue captureLevel2TradeQueueViewData(OpenCLExcuter* openCLExcuter, cv::Mat& grayImg, int identify); |
| | | |
| | | |
| | | |
| | |
| | | #include "L2TradeQueueUtil.h" |
| | | |
| | | list<ImgArea> L2TradeQueueUtil::splitElements(cv::Mat img) |
| | | #include "Win32Util.h" |
| | | |
| | | list<ImgArea> L2TradeQueueUtil::splitViewElements(cv::Mat img) |
| | | { |
| | | |
| | | list<int*> rowDataList = splitRows(img); |
| | |
| | | freeData(dataList); |
| | | free(rowData); |
| | | |
| | | if (false) { |
| | | if (FALSE) { |
| | | //保存 |
| | | int index = -1; |
| | | for (list<ImgArea>::iterator ele = posList.begin(); ele != posList.end(); ++ele) { |
| | |
| | | return posList; |
| | | } |
| | | |
| | | list<ImgArea> L2TradeQueueUtil::splitBuyQueue(cv::Mat img,int identify) |
| | | { |
| | | if (FALSE) |
| | | { |
| | | cv::imwrite(string("C:\\Users\\Administrator\\Desktop\\ocr\\trade_queue\\demo\\").append(to_string(identify)).append("_").append(to_string(rand())).append(".png"), img); |
| | | } |
| | | list<ImgArea> resultList; |
| | | //cv::Mat binary; |
| | | //二值化,方便处理 |
| | | //threshold(img, binary, _IMG_BINARY_THRESHOLD, 255, cv::THRESH_BINARY); |
| | | |
| | | |
| | | //分隔第一行 |
| | | int rows = img.rows; |
| | | int startCol = 0; |
| | | int endCol = img.cols - 1; |
| | | list<int*> rowDataList; |
| | | int full_start = -1; |
| | | int full_end = -1; |
| | | for (int r = 1; r < rows; r++) { |
| | | if (ImgDivider::isRowFull(img, r, startCol, endCol, 1,49,51)) { |
| | | if (full_start < 0) { |
| | | full_start = r; |
| | | } |
| | | if (r - full_start > 10) { |
| | | int* pos = (int*)malloc(sizeof(int) * 2); |
| | | pos[0] = full_start + 1; |
| | | pos[1] = r - 1; |
| | | rowDataList.push_back(pos); |
| | | full_start = r; |
| | | } |
| | | else { |
| | | full_start = r; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (rowDataList.size() < 1) { |
| | | throw string("无数据"); |
| | | } |
| | | endCol = img.cols - 1; |
| | | int index = 0; |
| | | for (list<int*>::iterator ele = rowDataList.begin(); ele != rowDataList.end(); ++ele) { |
| | | int* pos = *ele; |
| | | int startRow = pos[0]; |
| | | int endRow = pos[1]; |
| | | free(pos); |
| | | //去除上下空白,右侧留白10 |
| | | for (int i = startRow; i <= endRow; i++) { |
| | | if (!ImgDivider::isRowEmpty(img, i, startCol, endCol,1, _IMG_BINARY_THRESHOLD)) { |
| | | startRow = i; |
| | | break; |
| | | } |
| | | } |
| | | for (int i = endRow; i >= startRow; i--) { |
| | | if (!ImgDivider::isRowEmpty(img, i, startCol, endCol,1, _IMG_BINARY_THRESHOLD)) { |
| | | endRow = i; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | //if (identify == 4|| identify ==6) { |
| | | // printf("进入调试"); |
| | | //} |
| | | |
| | | if (endRow - startRow > 5) |
| | | { |
| | | |
| | | list<int*> elements = splitCols(img, startCol, startRow, endCol - 1, endRow, 3); |
| | | |
| | | for (list<int*>::iterator e = elements.begin(); e != elements.end(); ++e) { |
| | | int* ps = *e; |
| | | ImgArea area; |
| | | area.startx = ps[0]; |
| | | area.starty = ps[1]; |
| | | area.endx = ps[2]; |
| | | area.endy = ps[3]; |
| | | resultList.push_back(area); |
| | | free(ps); |
| | | if (FALSE) |
| | | { |
| | | cv::Mat sm = cv::Mat(img, cv::Rect(area.startx, area.starty, area.endx - area.startx + 1, area.endy - area.starty + 1)); |
| | | cv::imwrite(string("C:\\Users\\Administrator\\Desktop\\ocr\\trade_queue\\").append(to_string(index)).append(".png"), sm); |
| | | } |
| | | index++; |
| | | } |
| | | } |
| | | } |
| | | return resultList; |
| | | } |
| | | |
| | | HWND L2TradeQueueUtil::getTradeQueueBuyHWND(HWND tradeQueueHWND) |
| | | { |
| | | //暂时放在这儿 |
| | | HWND temp = NULL; |
| | | while (TRUE) |
| | | { |
| | | temp = FindWindowExA(tradeQueueHWND, temp, "#32770", "买卖队列"); |
| | | if (Win32Util::isWindowShow(temp) || temp <= 0) { |
| | | break; |
| | | } |
| | | } |
| | | if (temp <= 0) { |
| | | throw string("未找到买卖队列句柄"); |
| | | } |
| | | |
| | | HWND childTemp = NULL; |
| | | |
| | | |
| | | HWND rightHWND=NULL; |
| | | int rightPOS=-1; |
| | | |
| | | while (TRUE) |
| | | { |
| | | childTemp = FindWindowExA(temp, childTemp, "#32770", NULL); |
| | | if (childTemp <= 0) { |
| | | break; |
| | | } |
| | | else { |
| | | if (Win32Util::isWindowShow(childTemp)) { |
| | | //获取最右侧的内容框句柄 |
| | | RECT rect; |
| | | Win32Util::getWindowRect(childTemp, &rect); |
| | | if (rightPOS == -1) { |
| | | rightHWND = childTemp; |
| | | rightPOS = rect.right; |
| | | } |
| | | else if (rect.right > rightPOS) { |
| | | rightHWND = childTemp; |
| | | rightPOS = rect.right; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (rightHWND <= 0) { |
| | | throw string("买入成交队列句柄查找失败"); |
| | | } |
| | | rightHWND = FindWindowExA(rightHWND, NULL, "SysListView32", NULL); |
| | | if (rightHWND <= 0) { |
| | | throw string("买入成交队列句柄查找失败"); |
| | | } |
| | | return rightHWND; |
| | | } |
| | | |
| | | void L2TradeQueueUtil::filterTradeQueueBuyMat(cv::Mat& grayImg) |
| | | { |
| | | list<ImgArea> areas; |
| | | int startR = -1; |
| | | for (int r = 0; r < grayImg.rows; r++) { |
| | | int startc = -1; |
| | | int endc = -1; |
| | | bool empty = TRUE; |
| | | for (int c = 0; c < grayImg.cols; c++) { |
| | | uchar data = grayImg.ptr<uchar>(r)[c]; |
| | | if (data >= 178 && data <= 180) { |
| | | empty = FALSE; |
| | | if (startc < 0) { |
| | | startc = c; |
| | | endc = c; |
| | | } |
| | | endc = c; |
| | | } |
| | | else { |
| | | if (startc > 0 && endc - startc > 10 && startR < 0) { |
| | | ImgArea area; |
| | | area.startx = startc; |
| | | area.endx = endc; |
| | | area.starty = r; |
| | | area.endy = -1; |
| | | areas.push_back(area); |
| | | startc = -1; |
| | | endc = -1; |
| | | } |
| | | } |
| | | } |
| | | if (areas.size() > 0 && startR < 0) { |
| | | startR = r; |
| | | } |
| | | |
| | | if (!empty && areas.size() > 0) { |
| | | continue; |
| | | } |
| | | |
| | | if (startR > 0 && empty) { |
| | | printf("起始行%d, 结束行:%d 数据条数:%d\n", startR, r, areas.size()); |
| | | for (list<ImgArea>::iterator ele = areas.begin(); ele != areas.end(); ++ele) { |
| | | ImgArea area = *ele; |
| | | area.endy = r - 1; |
| | | printf("%d,%d,%d,%d\n", area.startx, area.starty, area.endx, area.endy); |
| | | for (int r = area.starty; r <= area.endy; r++) { |
| | | for (int c = area.startx; c <= area.endx; c++) { |
| | | uchar data = grayImg.ptr<uchar>(r)[c]; |
| | | if (data >= _IMG_BINARY_THRESHOLD) { |
| | | grayImg.ptr<uchar>(r)[c] = 0; |
| | | } |
| | | else { |
| | | grayImg.ptr<uchar>(r)[c] = 255; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | printf("------------------------\n"); |
| | | |
| | | startR = -1; |
| | | areas.clear(); |
| | | } |
| | | } |
| | | } |
| | | list<int*> L2TradeQueueUtil::splitRows(cv::Mat img) |
| | | { |
| | | list<int*> rowDataList; |
| | |
| | | return rowDataList; |
| | | } |
| | | |
| | | list<int*> L2TradeQueueUtil::splitCols(cv::Mat img, int startx, int starty, int endx, int endy) |
| | | list<int*> L2TradeQueueUtil::splitCols(cv::Mat img, int startx, int starty, int endx, int endy, int minContentWidth) |
| | | { |
| | | cv::imwrite("C:\\Users\\Administrator\\Desktop\\ocr\\l2_trade\\test.png", cv::Mat(img, cv::Rect(startx, starty, endx - startx, endy - starty))); |
| | | |
| | | if (FALSE) |
| | | { |
| | | cv::imwrite("C:\\Users\\Administrator\\Desktop\\ocr\\l2_trade\\test.png", cv::Mat(img, cv::Rect(startx, starty, endx - startx + 1, endy - starty + 1))); |
| | | } |
| | | list<int*> splitList; |
| | | int empty_start = -1; |
| | | int empty_end = -1; |
| | | int start_col = -1; |
| | | int end_col = -1; |
| | | for (int c = startx; c <= endx; c++) { |
| | | if (ImgDivider::isColEmpty(img, c, starty, endy)) { |
| | | if (ImgDivider::isColEmpty(img, c, starty, endy,_IMG_BINARY_THRESHOLD)) { |
| | | if (empty_start < 0) { |
| | | empty_start = c; |
| | | } |
| | | empty_end = c; |
| | | if (empty_end - empty_start > 10) { |
| | | if (end_col - start_col >= 6) { |
| | | if (end_col - start_col >= minContentWidth) { |
| | | int* itemData = (int*)malloc(sizeof(int) * 4); |
| | | itemData[0] = start_col; |
| | | itemData[1] = starty; |
| | |
| | | empty_end = -1; |
| | | } |
| | | } |
| | | if (end_col - start_col >= minContentWidth) { |
| | | int* itemData = (int*)malloc(sizeof(int) * 4); |
| | | itemData[0] = start_col; |
| | | itemData[1] = starty; |
| | | itemData[2] = empty_start - 1; |
| | | itemData[3] = endy; |
| | | splitList.push_back(itemData); |
| | | start_col = -1; |
| | | end_col = -1; |
| | | } |
| | | |
| | | return splitList; |
| | | } |
| | |
| | | //行分隔 |
| | | static list<int*> splitRows(cv::Mat img); |
| | | //列分隔 |
| | | static list<int*> splitCols(cv::Mat img,int startx,int starty,int endx,int endy); |
| | | static list<int*> splitCols(cv::Mat img,int startx,int starty,int endx,int endy,int minContentWidth=6); |
| | | |
| | | static void freeData(list<int*> dataList); |
| | | public: |
| | | // 分隔元素 |
| | | static list<ImgArea> splitElements(cv::Mat img); |
| | | // 分隔概览数据 |
| | | static list<ImgArea> splitViewElements(cv::Mat img); |
| | | |
| | | // 分隔买队列 |
| | | static list<ImgArea> splitBuyQueue(cv::Mat img,int index); |
| | | |
| | | //获取正在成交的队列 |
| | | static HWND getTradeQueueBuyHWND(HWND tradeQueueHWND); |
| | | |
| | | //过滤买入队列信息 |
| | | static void filterTradeQueueBuyMat(cv::Mat& grayImg); |
| | | |
| | | |
| | | }; |
| | |
| | | bool LimitUpCapture::kill; |
| | | |
| | | CallbackFun_Limit_Up LimitUpCapture::data_callback; |
| | | MatOcrFun LimitUpCapture::ocr_fun; |
| | | |
| | | std::list<cv::Point> LimitUpCapture::pointList; |
| | | |
| | |
| | | clock_t start = clock(); |
| | | try { |
| | | list<LimitUpData> codes = captureLimitUpCodes(); |
| | | cout << "耗时:" << clock() - start << " 数量:" << codes.size() << endl; |
| | | //cout << "耗时:" << clock() - start << " 数量:" << codes.size() << endl; |
| | | data_callback(codes, context); |
| | | codes.clear(); |
| | | } |
| | |
| | | |
| | | bool LimitUpCapture::pause; |
| | | |
| | | void LimitUpCapture::init(CallbackFun_Limit_Up callback, void* contex) { |
| | | void LimitUpCapture::init(CallbackFun_Limit_Up callback, MatOcrFun matMcrFun, void* contex) { |
| | | data_callback = callback; |
| | | ocr_fun = matMcrFun; |
| | | context = contex; |
| | | running = false; |
| | | kill = false; |
| | |
| | | throw string("未获取到内容窗口的菜单句柄"); |
| | | |
| | | //查找菜单的位置 |
| | | |
| | | cv::Mat grayImg = ImgUtil::grayImage(CaptureUtil::capture(menuWin)); |
| | | int full_start = -1; |
| | | int full_end = -1; |
| | | int start_row = -1; |
| | | int end_row = -1; |
| | | int count = 0; |
| | | |
| | | pointList.clear(); |
| | | for (int r = grayImg.rows - 1;r>=0;r --) { |
| | | if (ImgDivider::isRowFull(grayImg,r,0, grayImg.cols-1,2,33,48)) { |
| | | if (full_start < 0) |
| | | { |
| | | full_start = r; |
| | | full_end = r; |
| | | } |
| | | else { |
| | | full_end = r; |
| | | } |
| | | |
| | | if (start_row > 0 && end_row > 0 && (start_row - end_row) > 5) { |
| | | count++; |
| | | printf("%d-%d\n", start_row, end_row); |
| | | |
| | | full_start = r; |
| | | full_end = r; |
| | | string path = "C:\\Users\\Administrator\\Desktop\\ocr\\menu\\"; |
| | | path.append("menu_").append(to_string(count)).append(".jpg"); |
| | | |
| | | //cv::imwrite(path, cv::Mat(grayImg,cv::Rect(0,end_row,grayImg.cols,start_row-end_row))); |
| | | |
| | | pointList.push_back(cv::Point( ( 0 + grayImg.cols)/2, (start_row + end_row)/2)); |
| | | if (pointList.size() >= 2) { |
| | | break; |
| | | } |
| | | start_row = -1; |
| | | end_row = -1; |
| | | } |
| | | } |
| | | else { |
| | | if (full_start >= 0) |
| | | { |
| | | if (start_row < 0) |
| | | { |
| | | start_row = r; |
| | | end_row = r; |
| | | } |
| | | else { |
| | | end_row = r; |
| | | } |
| | | } |
| | | list<OCRResult> ocrResultList = ocr_fun("今日", grayImg); |
| | | if (ocrResultList.size() > 0) { |
| | | for (list<OCRResult>::iterator ele = ocrResultList.begin(); ele != ocrResultList.end(); ele++) { |
| | | OCRResult result = *ele; |
| | | pointList.push_back(cv::Point((result.rect.left+result.rect.right)/2, (result.rect.top + result.rect.bottom) / 2)); |
| | | ImgUtil::markMat(grayImg, cv::Rect(result.rect.left, result.rect.top, result.rect.right - result.rect.left +1, result.rect.bottom - result.rect.top + 1), 255, 1); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | //cv::imwrite("C:\\Users\\Administrator\\Desktop\\ocr\\menu.jpg", ); |
| | | |
| | | //保存临时图片 |
| | | //cv::imwrite("C:\\Users\\Administrator\\Desktop\\ocr\\menu.jpg", grayImg); |
| | | } |
| | | |
| | | bool LimitUpCapture::isRunning() { |
| | |
| | | |
| | | static CallbackFun_Limit_Up data_callback; |
| | | |
| | | static MatOcrFun ocr_fun; |
| | | |
| | | static void* context; |
| | | |
| | | static void _run(); |
| | |
| | | //是否暂停 |
| | | static bool pause; |
| | | |
| | | void init(CallbackFun_Limit_Up callback, void* context); |
| | | void init(CallbackFun_Limit_Up callback, MatOcrFun matMcrFun, void* context); |
| | | |
| | | //重新创建运行线程 |
| | | void reCreateRunning(); |
| | |
| | | clReleaseMemObject(memObject3); |
| | | clReleaseMemObject(memObject4); |
| | | clReleaseMemObject(memObject5); |
| | | std::cout << " 耗时:" << (clock() - time_0) << std::endl; |
| | | //std::cout << " 耗时:" << (clock() - time_0) << std::endl; |
| | | } |
| | | |
| | | void OpenCLExcuter::splitL2NumNew(cv::Mat img, IntDataInfo pos, UcharDataInfo result, UcharDataInfo types, unsigned char* zero, int num_width, int num_height, int ele_count_per_line, int length_per_num) { |
| | |
| | | excuteError(); |
| | | throw st; |
| | | } |
| | | std::cout << " 耗时:" << (clock() - time_0) << std::endl; |
| | | //std::cout << " 耗时:" << (clock() - time_0) << std::endl; |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | |
| | | |
| | | std::cout << " 耗时:" << (clock() - time_0) << std::endl; |
| | | //std::cout << " 耗时:" << (clock() - time_0) << std::endl; |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | |
| | | |
| | | std::cout << " 耗时:" << (clock() - time_0) << std::endl; |
| | | //std::cout << " 耗时:" << (clock() - time_0) << std::endl; |
| | | } |
| | | |
| | | |
| | |
| | | clReleaseMemObject(memObject2); |
| | | clReleaseMemObject(memObject3); |
| | | clReleaseMemObject(memObject4); |
| | | std::cout << " 耗时:" << (clock() - time_0) << std::endl; |
| | | //std::cout << " 耗时:" << (clock() - time_0) << std::endl; |
| | | } |
| | | catch (string st) { |
| | | clReleaseKernel(kernel); |
| | |
| | | clReleaseKernel(kernel); |
| | | } |
| | | catch (string st) { |
| | | //保存错误的图片 |
| | | //string path = "C:\\Users\\Administrator\\Desktop\\ocr\\error\\"; |
| | | //path.append(to_string(clock())).append("_"); |
| | | //path.append(to_string(rand())).append(".png"); |
| | | //cv::imwrite(path, img); |
| | | clReleaseMemObject(memObject1); |
| | | clReleaseMemObject(memObject2); |
| | | clReleaseKernel(kernel); |
| | |
| | | return nums; |
| | | } |
| | | |
| | | |
| | | //获取整个L2的代码选择区域 |
| | | list<GPCodeArea> splitL2WholeCateArea(cv::Mat img) { |
| | | int contentStartRow = -1; |
| | | int contentEndRow = -1; |
| | | for (int r = 5; r < img.rows; r++) { |
| | | if (ImgDivider::isRowFull(img, r, 10, 200, 2, 10, 30)) { |
| | | if (contentStartRow < 0) |
| | | { |
| | | contentStartRow = r; |
| | | } |
| | | else { |
| | | if (r - contentStartRow > 10) { |
| | | contentEndRow = r; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (contentStartRow < 0 || contentEndRow < 0) { |
| | | throw string("起始行或结束行分隔出错(23)"); |
| | | } |
| | | //分隔列 |
| | | list<int*> dataColIndexs; |
| | | int startf = -1; |
| | | int endf = -1; |
| | | int startIndex = -1; |
| | | for (int i = 10; i < img.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 (img.cols - startIndex > 50) { |
| | | |
| | | int* dd = (int*)malloc(sizeof(int) * 2); |
| | | |
| | | *dd = startIndex; |
| | | *(dd + 1) = img.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); |
| | | |
| | | int endRow = 0; |
| | | //判断结束行 |
| | | for (int r = contentStartRow + 10; r < img.rows; r++) { |
| | | bool full = ImgDivider::isRowFull(img, r, startx, endx, 2, 10, 30); |
| | | if (full) { |
| | | endRow = r; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | GPCodeArea area = GPCodeArea(); |
| | | area.startx = startx; |
| | | area.endx = endx; |
| | | area.starty = contentStartRow; |
| | | area.endy = contentEndRow; |
| | | areaList.push_back(area); |
| | | |
| | | free(*ele); |
| | | } |
| | | return areaList; |
| | | } |
| | | |
| | | //获取副屏2 |
| | | HWND THSActionUtil::getThirdWindow() { |
| | | list<HWND> wlist = Win32Util::searchWindow("同花顺("); |
| | |
| | | |
| | | |
| | | if (isL2Screen(str)) { |
| | | return hwnd; |
| | | //判断内容是否为L2的内容 |
| | | HWND mainWin = FindWindowExA(hwnd, NULL, "AfxFrameOrView100s", NULL); |
| | | HWND temp = NULL; |
| | | int content_count = 0; |
| | | while (TRUE) { |
| | | temp = FindWindowExA(mainWin, temp, "AfxWnd100s", NULL); |
| | | if (temp == NULL || temp <= 0) { |
| | | break; |
| | | } |
| | | if (Win32Util::isWindowShow(temp)) { |
| | | content_count++; |
| | | } |
| | | } |
| | | if (content_count >= 16) |
| | | { |
| | | return hwnd; |
| | | } |
| | | } |
| | | |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | bool THSActionUtil::checkEnv() { |
| | | |
| | | list<HWND> wlist = Win32Util::searchWindow("同花顺("); |
| | |
| | | Sleep(1000); |
| | | } |
| | | } |
| | | } |
| | | |
| | | bool THSActionUtil::correctL2ScreenPlate(MatOcrFun matOcrFun) |
| | | { |
| | | HWND mainPage = getL2Win(); |
| | | if (mainPage <= 0) { |
| | | throw string("L2屏未打开"); |
| | | } |
| | | //获取板块的Mat |
| | | HWND content = FindWindowExA(mainPage, NULL, "AfxFrameOrView100s", NULL); |
| | | //截图 |
| | | cv::Mat oimg = CaptureUtil::capture(content); |
| | | cv::Mat img = ImgUtil::grayImage(oimg); |
| | | oimg.release(); |
| | | //分隔图片 |
| | | list<GPCodeArea> areaList = splitL2WholeCateArea(img); |
| | | int index = 0; |
| | | for (list<GPCodeArea>::iterator e = areaList.begin(); e != areaList.end(); ++e) |
| | | { |
| | | GPCodeArea area = *e; |
| | | RECT plateRect; |
| | | Win32Util::getWindowRect(content, &plateRect); |
| | | //获取窗体位置 |
| | | try { |
| | | int rows = area.endy - area.starty + 1; |
| | | int cols = area.endx - area.startx + 1; |
| | | cv::Mat mat = cv::Mat::zeros(rows, cols, CV_8UC1); |
| | | cv::Mat mat1 = cv::Mat(img,cv::Rect(area.startx, area.starty, cols, rows)); |
| | | uchar *datas =(uchar *) malloc(sizeof(uchar)*mat.rows* mat.cols); |
| | | for (int r = 0; r < rows; r++) { |
| | | for (int c = 0; c < cols; c++) { |
| | | datas[r * cols + c] = mat1.ptr<uchar>(r)[c]; |
| | | } |
| | | } |
| | | mat.data = datas; |
| | | list<OCRResult> results = matOcrFun("首板关注", mat); |
| | | free(datas); |
| | | //获取点击位置 |
| | | for (list<OCRResult>::iterator ele = results.begin(); ele != results.end(); ++ele) |
| | | { |
| | | OCRResult result = *ele; |
| | | int x = area.startx + result.rect.left; |
| | | int y = area.starty + result.rect.top; |
| | | cv::Rect ocrRect = cv::Rect(x, y, result.rect.right - result.rect.left + 1, result.rect.bottom - result.rect.top + 1); |
| | | //判断是否选中,选中后背景颜色的色值为15,否则就未选中 |
| | | int selectColorCount = 0; |
| | | for (int r = ocrRect.y; r < ocrRect.y + ocrRect.height; r++) { |
| | | for (int c = ocrRect.x; c < ocrRect.x + ocrRect.width; c++) { |
| | | if (img.ptr<uchar>(r)[c] == 15) { |
| | | selectColorCount++; |
| | | } |
| | | } |
| | | } |
| | | |
| | | //ImgUtil::markMat(img,ocrRect,255,1); |
| | | Win32Util::showWindow(content); |
| | | Win32Util::focus(content); |
| | | |
| | | // 未被选中 |
| | | if (selectColorCount < 20) |
| | | { |
| | | for (int i = 0; i < 2; i++) |
| | | { |
| | | Win32Util::click(plateRect.left + x + 10, plateRect.top + y + (result.rect.bottom - result.rect.top) / 2, 100); |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | catch (string st) { |
| | | printf(st.c_str()); |
| | | return FALSE; |
| | | } |
| | | } |
| | | if (FALSE) { |
| | | string path = string("D:/test_mark.png"); |
| | | cv::imwrite(path, img); |
| | | } |
| | | return TRUE; |
| | | } |
| | | |
| | | void THSActionUtil::openSecondScreen() { |
| | |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | //分隔L2数据的目录 |
| | | std::list<GPCodeArea> splitL2Cate(cv::Mat img) { |
| | | int cols = img.cols; |
| | |
| | | } |
| | | return areaList; |
| | | } |
| | | |
| | | |
| | | |
| | | //分隔L2交易队列 |
| | |
| | | //L2数据有效 |
| | | int cateIndex; |
| | | }; |
| | | typedef list<OCRResult> (*MatOcrFun)(string key_regex,cv::Mat mat); |
| | | //同花顺事件 |
| | | class THSActionUtil |
| | | { |
| | |
| | | |
| | | //打开同花顺的副屏幕 |
| | | static void openL2Screen(); |
| | | //矫正L2代码板块(选中首版待选) |
| | | static bool correctL2ScreenPlate(MatOcrFun matOcrFun); |
| | | static void openSecondScreen(); |
| | | static void openThirdScreen(); |
| | | static void openTradeSuccessScreen(); |
| | |
| | | clock_t start = clock(); |
| | | try { |
| | | list<TradeSuccessData> datas = captureTradeSuccessInfo(); |
| | | cout << "耗时:" << clock() - start << " 数量:" << datas.size() << endl; |
| | | //cout << "耗时:" << clock() - start << " 数量:" << datas.size() << endl; |
| | | data_callback_success(datas, context); |
| | | datas.clear(); |
| | | } |
| | |
| | | try { |
| | | list<TradeDelegateData> datas = captureSimpleTradeDelegateInfo(); |
| | | string money = getSimpleAvaiableMoney(); |
| | | cout << "耗时:" << clock() - start << " 数量:" << datas.size() << endl; |
| | | //cout << "耗时:" << clock() - start << " 数量:" << datas.size() << endl; |
| | | data_callback_delegate(datas, money, context); |
| | | datas.clear(); |
| | | } |
| | |
| | | } |
| | | |
| | | |
| | | } |
| | | void TradeListCapture::selectTradeSimpleDelegate(MatOcrFun matMcrFun) |
| | | { |
| | | try { |
| | | //刷新窗口 |
| | | refreshTradeSimpleDelegateHWND(); |
| | | } |
| | | catch (...) { |
| | | |
| | | } |
| | | HWND win = THSActionUtil::getTradeSimpleDelegateWindow(); |
| | | HWND menuWin = TradeListCapture::getSimpleTradeLeftMenu(win); |
| | | if (menuWin > 0) { |
| | | cv::Mat img = CaptureUtil::capture(menuWin); |
| | | cv::Mat grayImg = ImgUtil::grayImage(img); |
| | | img.release(); |
| | | list<OCRResult> resultList = matMcrFun("当日委托", grayImg); |
| | | if (resultList.size() > 0) { |
| | | OCRResult result = *(resultList.begin()); |
| | | RECT menuWinRect; |
| | | Win32Util::getWindowRect(menuWin, &menuWinRect); |
| | | int x = menuWinRect.left + result.rect.left + (result.rect.right - result.rect.left) / 2; |
| | | int y = menuWinRect.top + result.rect.top + (result.rect.bottom - result.rect.top) / 2; |
| | | //点击 |
| | | Win32Util::click(x, y, 10); |
| | | } |
| | | } |
| | | } |
| | | void TradeListCapture::selectTradeSuccess(MatOcrFun matMcrFun) |
| | | { |
| | | try { |
| | | //刷新窗口 |
| | | refreshTradeSuccessHWND(); |
| | | } |
| | | catch (...) { |
| | | |
| | | } |
| | | HWND win = THSActionUtil::getTradeSuccessWindow(); |
| | | HWND menuWin = TradeListCapture::getSimpleTradeLeftMenu(win); |
| | | if (menuWin > 0) { |
| | | cv::Mat img = CaptureUtil::capture(menuWin); |
| | | cv::Mat grayImg = ImgUtil::grayImage(img); |
| | | img.release(); |
| | | list<OCRResult> resultList = matMcrFun("当日成交", grayImg); |
| | | if (resultList.size() > 0) { |
| | | OCRResult result = *(resultList.begin()); |
| | | RECT menuWinRect; |
| | | Win32Util::getWindowRect(menuWin, &menuWinRect); |
| | | int x = menuWinRect.left + result.rect.left + (result.rect.right - result.rect.left) / 2; |
| | | int y = menuWinRect.top + result.rect.top + (result.rect.bottom - result.rect.top) / 2; |
| | | //点击 |
| | | Win32Util::click(x, y, 10); |
| | | } |
| | | } |
| | | } |
| | | void TradeListCapture::reCreateTradeSuccessRunning() |
| | | { |
| | |
| | | std::advance(end, -1); |
| | | int end_start = (*end)[0]; |
| | | std::advance(end, -1); |
| | | if (end_start - (*end)[1]>15) { |
| | | if (end_start - (*end)[1] > 15) { |
| | | //删除最后1条数据 |
| | | std::advance(end, 1); |
| | | free(*end); |
| | |
| | | |
| | | void init(CallbackFun_Trade_Success callback_s, CallbackFun_Trade_Delegate callback_d, void* context); |
| | | |
| | | //选中精简版交易界面中的当日委托按钮 |
| | | void selectTradeSimpleDelegate(MatOcrFun matMcrFun); |
| | | |
| | | //选中交易界面中的当日成交按钮 |
| | | void selectTradeSuccess(MatOcrFun matMcrFun); |
| | | |
| | | //重新创建线程 |
| | | void reCreateTradeSuccessRunning(); |
| | | void reCreateTradeDelegateRunning(); |
| | |
| | | ImgUtil::init(); |
| | | OpenCLExcuter* openCLExcuter = new OpenCLExcuter(); |
| | | openCLExcuter->init(); |
| | | cv::Mat img = cv::imread("C:\\Users\\Administrator\\Desktop\\ocr\\trade\\Snipaste_2023-01-13_18-23-34.png"); |
| | | cv::Mat img = cv::imread("C:\\Users\\Administrator\\Desktop\\ocr\\trade_queue\\demo\\24084.jpg"); |
| | | uchar* datas = (uchar*)malloc(sizeof(uchar) * img.rows * img.cols); |
| | | if (img.channels() == 4) |
| | | { |
| | |
| | | cv::Mat binary; |
| | | threshold(img1, binary, 96, 255, cv::THRESH_BINARY); |
| | | |
| | | cv::imwrite("C:\\Users\\Administrator\\Desktop\\ocr\\trade\\Snipaste_2023-01-13_18-23-34_gray.png", img1); |
| | | cv::imwrite("C:\\Users\\Administrator\\Desktop\\ocr\\trade_queue\\demo\\24084_gray.png", img1); |
| | | |
| | | } |
| | | |
| | | void testSplit() { |
| | | |
| | | ImgUtil::init(); |
| | | L2TradeQueueUtil::splitElements(cv::imread("C:\\Users\\Administrator\\Desktop\\ocr\\l2_trade_queue_2.png", cv::IMREAD_GRAYSCALE)); |
| | | //list<ImgArea> areas = L2TradeQueueUtil::splitBuyQueue(cv::imread("C:\\Users\\Administrator\\Desktop\\ocr\\trade_queue\\demo\\test.png", cv::IMREAD_GRAYSCALE),0); |
| | | |
| | | list<ImgArea> areas = L2TradeQueueUtil::splitViewElements(cv::imread("C:\\Users\\Administrator\\Desktop\\ocr\\trade_queue\\demo\\7_19353.png", cv::IMREAD_GRAYSCALE)); |
| | | } |
| | | |
| | | void testCaptureL2Trade() { |
| | |
| | | OpenCLExcuter* openCLExcuter = new OpenCLExcuter(); |
| | | openCLExcuter->init(); |
| | | L2DataCapture *capture = new L2DataCapture(); |
| | | cv::Mat img = cv::imread("C:\\Users\\Administrator\\Desktop\\ocr\\l2_trade_queue_3.png"); |
| | | L2TradeQueue tradeQueue = capture->captureLevel2TradeQueueData(openCLExcuter, img, 0); |
| | | cv::Mat img = cv::imread("C:\\Users\\Administrator\\Desktop\\ocr\\trade_queue\\Snipaste_2023-02-02_15-32-01.png"); |
| | | //L2TradeQueue tradeQueue = capture->captureLevel2TradeQueueData(openCLExcuter, img, 0); |
| | | printf("\n"); |
| | | } |
| | | |
| | |
| | | capture->captureTradeSuccessInfo(cv::imread("C:\\Users\\Administrator\\Desktop\\ocr\\trade\\Snipaste_2022-12-23_09-39-02.png")); |
| | | } |
| | | |
| | | void markImg() { |
| | | cv::Mat mat = cv::imread("C:\\Users\\Administrator\\Desktop\\ocr\\trade_queue\\Snipaste_2023-02-02_15-22-58.png", cv::IMREAD_GRAYSCALE); |
| | | mat = ImgUtil::markMat(mat,cv::Rect(60,50,100,10),255,1); |
| | | cv::imwrite("C:\\Users\\Administrator\\Desktop\\ocr\\trade_queue\\mark.png", mat); |
| | | } |
| | | |
| | | |
| | | int main() { |
| | | grayImg(); |
| | | markImg(); |
| | | return 1; |
| | | //testL2(); |
| | | //if (TRUE) { |
| | |
| | | |
| | | //json对象转为字符串 |
| | | static std::string toJsonStr(Json::Value json) { |
| | | clock_t start_time = clock(); |
| | | Json::StreamWriterBuilder writerBuilder; |
| | | //不自动换行 |
| | | writerBuilder.settings_["indentation"] = ""; |
| | |
| | | jsonWriter->write(json, &os); |
| | | string jsonStr = os.str(); |
| | | //释放资源 |
| | | jsonWriter.reset(); |
| | | //jsonWriter.reset(); |
| | | //cout << "json转字符串耗时:"<< clock()- start_time << endl; |
| | | return jsonStr; |
| | | } |
| | | |
| | | static std::string loadL2Data(int clientID, int channel, string code, long captureTime, long processTime, std::list<TradeData*> dataList) { |
| | | Json::Value data; |
| | | data["channel"] = channel; |
| | | data["code"] = code; |
| | | data["captureTime"] = captureTime; |
| | | data["processTime"] = processTime; |
| | | data["data"] = toJson(dataList); |
| | | Json::Value root; |
| | | root["type"] = 0; |
| | | root["client"] = clientID; |
| | | root["data"] = data; |
| | | return toJsonStr(root); |
| | | //Json::Value data; |
| | | //data["channel"] = channel; |
| | | //data["code"] = code; |
| | | //data["captureTime"] = captureTime; |
| | | //data["processTime"] = processTime; |
| | | //data["data"] = toJson(dataList); |
| | | //Json::Value root; |
| | | //root["type"] = 0; |
| | | //root["client"] = clientID; |
| | | //root["data"] = data; |
| | | //return toJsonStr(root); |
| | | string st = "{"; |
| | | st.append("\"type\":0,"); |
| | | st.append("\"client\":").append(to_string(clientID)).append(","); |
| | | st.append("\"data\":{"); |
| | | st.append("\"channel\":").append(to_string(channel)).append(","); |
| | | st.append("\"code\":").append("\"").append(code).append("\"").append(","); |
| | | st.append("\"captureTime\":").append(to_string(captureTime)).append(","); |
| | | st.append("\"processTime\":").append(to_string(channel)).append(","); |
| | | st.append("\"data\":["); |
| | | int index = 0; |
| | | for (std::list<TradeData*>::iterator ele = dataList.begin(); ele != dataList.end(); ele++) { |
| | | index++; |
| | | st.append("{"); |
| | | st.append("\"time\":").append("\"").append((*ele)->time).append("\"").append(","); |
| | | st.append("\"price\":").append("\"").append((*ele)->price).append("\"").append(","); |
| | | st.append("\"num\":").append(to_string((*ele)->num)).append(","); |
| | | st.append("\"limitPrice\":").append(to_string((*ele)->limitPrice)).append(","); |
| | | st.append("\"operateType\":").append(to_string((*ele)->operateType)).append(","); |
| | | st.append("\"cancelTime\":").append(to_string((*ele)->cancelTime)).append(","); |
| | | st.append("\"cancelTimeUnit\":").append(to_string((*ele)->cancelTimeUnit)); |
| | | st.append("}"); |
| | | if (index != dataList.size()) { |
| | | st.append(","); |
| | | } |
| | | } |
| | | st.append("]"); |
| | | st.append("}}"); |
| | | return st; |
| | | } |
| | | |
| | | |
| | |
| | | _data["sellOnePrice"] = tradeQueue.sellOnePrice; |
| | | _data["sellOneVolumn"] = tradeQueue.sellOneVolumn; |
| | | _data["sellTime"] = tradeQueue.sellTime; |
| | | Json::Value buyQueue; |
| | | int index = 0; |
| | | for (list<string>::iterator ele = tradeQueue.buyQueue.begin(); ele != tradeQueue.buyQueue.end(); ++ele) { |
| | | buyQueue[index++] = atoi((*ele).c_str()); |
| | | } |
| | | _data["buyQueue"] = buyQueue; |
| | | |
| | | |
| | | data["data"] = _data; |
| | | Json::Value root; |
| | |
| | | return root; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | static string jsonValue2String(Json::Value value) { |
| | | Json::FastWriter fastWriter; |
| | | std::string output = fastWriter.write(value); |
New file |
| | |
| | | #include "pch.h" |
| | | #include "OcrUtil.h" |
| | | #include "SocketManager.h" |
| | | |
| | | list<OCRResult> OcrUtil::mat_ocr(string key_regex, cv::Mat mat) |
| | | { |
| | | |
| | | int len = mat.rows * mat.cols; |
| | | chrono::time_point<chrono::system_clock, chrono::microseconds> tpMicro |
| | | = chrono::time_point_cast<chrono::microseconds>(chrono::system_clock::now()); |
| | | // (微秒精度的)时间点 => (微秒精度的)时间戳 |
| | | time_t totalMicroSeconds = tpMicro.time_since_epoch().count(); |
| | | string matId = string(to_string(totalMicroSeconds)).append("_").append(to_string(mat.rows)).append("x").append(to_string(mat.cols)).append("_").append(to_string(rand())); |
| | | |
| | | int BUFFER_SIZE = 1024 * 2; |
| | | int maxSize = mat.rows * mat.cols; |
| | | int maxIndex = maxSize / BUFFER_SIZE; |
| | | |
| | | //生成matID |
| | | //分块发送,每一行为1块 |
| | | for (int index = 0; index <= maxIndex; index++) { |
| | | Json::Value array; |
| | | for (int c = 0; c < BUFFER_SIZE; c++) { |
| | | int dataIndex = index * BUFFER_SIZE + c; |
| | | if (dataIndex >= maxSize) { |
| | | break; |
| | | } |
| | | array[c] = mat.data[index * BUFFER_SIZE + c]; |
| | | } |
| | | Json::Value data; |
| | | data["data"] = array; |
| | | data["matId"] = matId; |
| | | data["index"] = index; |
| | | data["maxIndex"] = maxIndex; |
| | | data["width"] = mat.cols; |
| | | data["height"] = mat.rows; |
| | | data["key"] = key_regex.c_str(); |
| | | Json::Value root; |
| | | root["data"] = data; |
| | | root["type"] = 100; |
| | | string result_str = JsonUtil::toJsonStr(root); |
| | | for (int i = 0; i < 10; i++) |
| | | { |
| | | try { |
| | | string result = SocketManager::sendOcrMsg(result_str.c_str()); |
| | | return parseOCRResult(result); |
| | | } |
| | | catch (int code) { |
| | | if (code == -1) { |
| | | //数据不完整 |
| | | Sleep(100); |
| | | continue; |
| | | } |
| | | else if (code == 1) { |
| | | //等待继续上传 |
| | | break; |
| | | } |
| | | else { |
| | | break; |
| | | } |
| | | } |
| | | catch (...) { |
| | | } |
| | | } |
| | | } |
| | | throw string("识别失败"); |
| | | } |
New file |
| | |
| | | #pragma once |
| | | #include <string> |
| | | #include "JsonUtil.h" |
| | | |
| | | class OcrUtil |
| | | { |
| | | private: |
| | | static list<OCRResult> parseOCRResult(string result) { |
| | | Json::Value data = JsonUtil::parseJson(result); |
| | | if (data["code"].asInt() == 0) { |
| | | list<OCRResult> results; |
| | | data = data["data"]["datas"]; |
| | | if (data.size() > 0) { |
| | | for (int i = 0; i < data.size(); i++) { |
| | | Json::Value item = data[i]; |
| | | string text = item[0].asString(); |
| | | Json::Value left = item[1][0]; |
| | | Json::Value top = item[1][1]; |
| | | Json::Value right = item[1][2]; |
| | | Json::Value bottom = item[1][3]; |
| | | RECT rect; |
| | | rect.left = left[0].asInt(); |
| | | rect.top = left[1].asInt(); |
| | | rect.right = right[0].asInt(); |
| | | rect.bottom = right[1].asInt(); |
| | | results.push_back(OCRResult({ text,rect })); |
| | | } |
| | | return results; |
| | | } |
| | | |
| | | } |
| | | else { |
| | | throw data["code"].asInt(); |
| | | } |
| | | throw string("识别不匹配"); |
| | | } |
| | | public: |
| | | static list<OCRResult> mat_ocr(string key_regex, cv::Mat mat); |
| | | |
| | | |
| | | }; |
| | | |
| | |
| | | } |
| | | return string(buffer); |
| | | } |
| | | |
| | | string SocketManager::sendOcrMsg(const char* msg) |
| | | { |
| | | WSADATA wsd; |
| | | WSAStartup(MAKEWORD(2, 2), &wsd); |
| | | SOCKET m_SockClient; |
| | | m_SockClient = socket(AF_INET, SOCK_STREAM, 0); |
| | | sockaddr_in clientaddr; |
| | | clientaddr.sin_family = AF_INET; |
| | | clientaddr.sin_port = htons(OCR_PORT); |
| | | clientaddr.sin_addr.S_un.S_addr = inet_addr(ADDR.c_str()); |
| | | |
| | | connect(m_SockClient, (sockaddr*)&clientaddr, sizeof(clientaddr)); |
| | | char buffer[1024]; |
| | | |
| | | int result = send(m_SockClient, msg, strlen(msg), 0); |
| | | if (result < 0) { |
| | | throw string("发送失败"); |
| | | } |
| | | |
| | | int num = recv(m_SockClient, buffer, 1024, 0); |
| | | closesocket(m_SockClient); |
| | | if (num < 0) { |
| | | throw string("未接收到信息"); |
| | | } |
| | | return string(buffer); |
| | | } |
| | |
| | | static void runSocketServer(void* context); |
| | | static void processMsg(SOCKET client, void* context); |
| | | static const int PORT = 9001; |
| | | static const int OCR_PORT = 9002; |
| | | |
| | | sockaddr_in clientaddr; |
| | | SOCKET getClient(int p); |
| | |
| | | |
| | | static string sendMsg(const char*); |
| | | |
| | | static string sendOcrMsg(const char*); |
| | | |
| | | |
| | | }; |
| | | |
| | |
| | | <ClInclude Include="lib_json\include\json\writer.h" /> |
| | | <ClInclude Include="loginDlg.h" /> |
| | | <ClInclude Include="NetWorkUtil.h" /> |
| | | <ClInclude Include="OcrUtil.h" /> |
| | | <ClInclude Include="pch.h" /> |
| | | <ClInclude Include="Resource.h" /> |
| | | <ClInclude Include="SocketManager.h" /> |
| | |
| | | <ClCompile Include="appDlg.cpp" /> |
| | | <ClCompile Include="loginDlg.cpp" /> |
| | | <ClCompile Include="NetWorkUtil.cpp" /> |
| | | <ClCompile Include="OcrUtil.cpp" /> |
| | | <ClCompile Include="pch.cpp"> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> |
| | | <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> |
| | |
| | | <ClInclude Include="StringUtils.h"> |
| | | <Filter>头文件</Filter> |
| | | </ClInclude> |
| | | <ClInclude Include="OcrUtil.h"> |
| | | <Filter>头文件</Filter> |
| | | </ClInclude> |
| | | </ItemGroup> |
| | | <ItemGroup> |
| | | <ClCompile Include="app.cpp"> |
| | |
| | | <ClCompile Include="StringUtils.cpp"> |
| | | <Filter>源文件</Filter> |
| | | </ClCompile> |
| | | <ClCompile Include="OcrUtil.cpp"> |
| | | <Filter>源文件</Filter> |
| | | </ClCompile> |
| | | </ItemGroup> |
| | | <ItemGroup> |
| | | <ResourceCompile Include="app.rc"> |
| | |
| | | #endif |
| | | #include "JsonUtil.h" |
| | | #include <exception> |
| | | #include "OcrUtil.h" |
| | | |
| | | |
| | | #ifdef _DEBUG |
| | |
| | | } |
| | | } |
| | | autoMsgStatic.SetWindowTextW(_T("等待打开副屏1...")); |
| | | |
| | | |
| | | for (int i = 0; i < 5; i++) { |
| | | HWND second = THSActionUtil::getSecondWindow(); |
| | | if (second > 0) { |
| | |
| | | THSActionUtil::openSecondScreen(); |
| | | Sleep(1000); |
| | | } |
| | | |
| | | |
| | | autoMsgStatic.SetWindowTextW(_T("副屏1已打开...")); |
| | | Sleep(1000); |
| | | // 开启 涨停识别 |
| | |
| | | CappDlg::OnBnClickedButton12(); |
| | | autoMsgStatic.SetWindowTextW(_T("启动涨停启动成功")); |
| | | |
| | | // 开启委托识别 |
| | | // 开启委托识别 |
| | | |
| | | // 开启交易成功识别 |
| | | // 开启交易成功识别 |
| | | |
| | | |
| | | |
| | |
| | | |
| | | |
| | | void CappDlg::OnL2DataCallback(int index, string code, long captureTime, long processTime, list<TradeData*> dataList, void* context) { |
| | | clock_t time_start = clock(); |
| | | //转为json |
| | | CappDlg* app = (CappDlg*)context; |
| | | //cout << "回调:" << std::this_thread::get_id() << ":" << index << endl; |
| | | CButton* btn = (CButton*)app->GetDlgItem(IDC_CHECK1); |
| | | bool check = btn->GetCheck(); |
| | | if (check) { |
| | | if (index == 0) |
| | | { |
| | | cout << "\n*****状态判断用时*****:" << (clock() - time_start) << endl; |
| | | } |
| | | time_start = clock(); |
| | | string data = JsonUtil::loadL2Data(app->clientNum, index, code, captureTime, processTime, dataList); |
| | | for (list<TradeData*>::iterator el = dataList.begin(); el != dataList.end();++el) { |
| | | for (list<TradeData*>::iterator el = dataList.begin(); el != dataList.end(); ++el) { |
| | | delete (*el); |
| | | } |
| | | dataList.clear(); |
| | | clock_t time_start = clock(); |
| | | if (index == 0) |
| | | { |
| | | cout << "\n*****组装数据处理用时*****:" << (clock() - time_start) << endl; |
| | | } |
| | | |
| | | time_start = clock(); |
| | | try { |
| | | app->socketManager->sendMsg(index, data.c_str()); |
| | | } |
| | |
| | | app->socketManager->resetClient(index); |
| | | app->socketManager->Connect(index); |
| | | } |
| | | //cout << "*****数据处理时间:" << (clock() - time_start) << endl; |
| | | if (index == 0) |
| | | { |
| | | cout << "\n*****服务端数据处理时间*****:" << (clock() - time_start) << endl; |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | clock_t time_start = clock(); |
| | | |
| | | try { |
| | | app->socketManager->sendMsg(8, data.c_str()); |
| | | SocketManager::sendMsg(data.c_str()); |
| | | } |
| | | catch (string st) { |
| | | //重新连接服务器 |
| | | app->socketManager->resetClient(8); |
| | | app->socketManager->Connect(8); |
| | | |
| | | } |
| | | |
| | | |
| | | //上传账户可用余额 |
| | | data = JsonUtil::loadAvailableMoney(app->clientNum, money); |
| | | try { |
| | | app->socketManager->sendMsg(8, data.c_str()); |
| | | SocketManager::sendMsg(data.c_str()); |
| | | } |
| | | catch (string st) { |
| | | app->socketManager->resetClient(8); |
| | | app->socketManager->Connect(8); |
| | | } |
| | | |
| | | cout << "####交易成功数据处理时间:" << (clock() - time_start) << endl; |
| | |
| | | //app->onlineCheck.PostMessage(WM_LBUTTONUP, 0, 0); |
| | | RECT rect; |
| | | Win32Util::getWindowRect(app->onlineCheck.m_hWnd, &rect); |
| | | Win32Util::click((rect.left + rect.right )/ 2, (rect.top + rect.bottom) / 2, 10); |
| | | |
| | | Win32Util::click((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2, 10); |
| | | |
| | | } |
| | | else if (action == "repairL2Data") { |
| | | //修正代码与L2行情代码不对应 或者 L2行情无数据的情况 |
| | |
| | | return string(); |
| | | } |
| | | |
| | | list<OCRResult> CappDlg::MatOcr(string key_regex, cv::Mat mat) |
| | | { |
| | | return OcrUtil::mat_ocr(key_regex, mat); |
| | | } |
| | | |
| | | //心跳信号 |
| | | void CappDlg::onHeartbeat() { |
| | | //5s一次心跳 |
| | |
| | | if (!limitUpCapture->isInited()) |
| | | { |
| | | try { |
| | | limitUpCapture->init(OnLimitUpDataCallback, this); |
| | | limitUpCapture->init(OnLimitUpDataCallback, MatOcr, this); |
| | | } |
| | | catch (string st) { |
| | | if (notify) |
| | |
| | | Win32Util::showWindow(l2); |
| | | //初始化l2的各个窗口句柄 |
| | | app->capture->refreshHWND(); |
| | | //选中板块 |
| | | try { |
| | | //THSActionUtil::correctL2ScreenPlate(OcrUtil::mat_ocr); |
| | | } |
| | | catch (string st) { |
| | | |
| | | } |
| | | } |
| | | |
| | | HWND second = THSActionUtil::getSecondWindow(); |
| | |
| | | //将副屏1与副屏2缩小为屏幕的一半 |
| | | Win32Util::moveWin(second, device_pos.x, device_pos.y + device_height / 2, device_width / 2 - 50, device_height / 2); |
| | | Win32Util::moveWin(third, device_pos.x + device_width / 2 + 30, device_pos.y + device_height / 2, device_width / 2 - 50, device_height / 2); |
| | | |
| | | try { |
| | | Sleep(500); |
| | | THSActionUtil::correctL2ScreenPlate(OcrUtil::mat_ocr); |
| | | } |
| | | catch (...) { |
| | | |
| | | } |
| | | } |
| | | |
| | | void CappDlg::autoStartL2(void* context) |
| | |
| | | app->socketManager->resetClient(8); |
| | | app->socketManager->Connect(8); |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | void CappDlg::autoStartTradeDelegate(void* context) |
| | |
| | | { |
| | | try { |
| | | socketManager->sendMsg(i, "test"); |
| | | scount++; |
| | | |
| | | scount++; |
| | | |
| | | } |
| | | catch (string st) { |
| | | |
| | |
| | | { |
| | | socketManager->sendMsg(i, "test"); |
| | | scount++; |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | |
| | | void CappDlg::OnBnClickedButton20() |
| | | { |
| | | try { |
| | | THSActionUtil::checkEnv(); |
| | | checkTHSEnv(this); |
| | | AfxMessageBox(_T("检测通过")); |
| | | } |
| | | catch (const string& st) { |
| | |
| | | //启动任务 |
| | | void CappDlg::OnBnClickedButton5() |
| | | { |
| | | //检测环境 |
| | | |
| | | try { |
| | | THSActionUtil::checkEnv(); |
| | | } |
| | | catch (string st) { |
| | | CString msg(st.c_str()); |
| | | AfxMessageBox(msg); |
| | | return; |
| | | } |
| | | |
| | | CButton* btn = (CButton*)GetDlgItem(IDC_BUTTON5); |
| | | |
| | |
| | | } |
| | | } |
| | | if (!capture->isRunning()) { |
| | | |
| | | // 检测环境 |
| | | checkTHSEnv(this); |
| | | |
| | | try { |
| | | map<int, string> result = THSActionUtil::getListenL2GPCodes(recognitionManager); |
| | |
| | | |
| | | //TODO 测试图片切割 |
| | | //THSActionUtil::getListenL2GPAreaActionBar(); |
| | | // 检测同花顺板块是否选中 |
| | | try { |
| | | Sleep(500); |
| | | THSActionUtil::correctL2ScreenPlate(OcrUtil::mat_ocr); |
| | | } |
| | | catch (...) { |
| | | |
| | | } |
| | | |
| | | } |
| | | else { |
| | |
| | | if (!limitUpCapture->isInited()) { |
| | | try |
| | | { |
| | | limitUpCapture->init(OnLimitUpDataCallback, this); |
| | | limitUpCapture->init(OnLimitUpDataCallback,MatOcr,this); |
| | | |
| | | } |
| | | catch (string st) |
| | |
| | | AfxMessageBox(msg); |
| | | return; |
| | | } |
| | | //如果已经打开了远航版的交易,就需要点击当日委托 |
| | | try { |
| | | tradeListCapture->selectTradeSuccess(MatOcr); |
| | | } |
| | | catch (...) { |
| | | |
| | | } |
| | | |
| | | tradeListCapture->startTradeSuccess(); |
| | | tradeBtn.SetWindowTextW(_T("暂停成交识别任务")); |
| | |
| | | |
| | | //打开同花顺远航版的委托界面 |
| | | HWND win = 0; |
| | | if (win <= 0) { |
| | | //判断是否已经打开了同花顺远航版 |
| | | for (int i = 0; i < 10; i++) |
| | | { |
| | | win = THSActionUtil::getTradeSimpleDelegateWindow(); |
| | | if (win <= 0) |
| | | { |
| | | list<HWND> wlist = Win32Util::searchWindow("同花顺远航版"); |
| | | if (wlist.size() > 0) { |
| | | HWND mainWin = *(wlist.begin()); |
| | | //按F12 |
| | | Win32Util::sendMessage(mainWin, WM_KEYDOWN, VK_F12, 0); |
| | | Win32Util::sendMessage(mainWin, WM_KEYUP, VK_F12, 0); |
| | | //等待反应 |
| | | Sleep(500); |
| | | } |
| | | else { |
| | | //等待远航版打开 |
| | | Sleep(1000); |
| | | } |
| | | } |
| | | else { |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | //如果已经打开了远航版的交易,就需要点击当日委托 |
| | | try { |
| | | HWND menuWin = TradeListCapture::getSimpleTradeLeftMenu(win); |
| | | if (menuWin > 0) { |
| | | cv::Mat img = CaptureUtil::capture(menuWin); |
| | | string result = JsonUtil::loadOcrData(clientNum, img, "当日委托"); |
| | | result = socketManager->sendMsg(result.c_str()); |
| | | Json::Value root = JsonUtil::parseJson(result); |
| | | if (root["code"] == 0) { |
| | | //图像识别成功 |
| | | Json::Value datas = root["data"]["datas"]; |
| | | Json::Value ps = datas[0]["position"]; |
| | | //position格式:[[0,13],[12,13],[12,15],[0,15]] |
| | | //获取中心点 |
| | | int x = (ps[0][0].asInt() + ps[1][0].asInt()) / 2; |
| | | int y= (ps[0][1].asInt() + ps[2][1].asInt()) / 2; |
| | | RECT rect; |
| | | Win32Util::getWindowRect(menuWin,&rect); |
| | | x = rect.left + x; |
| | | y = rect.top + y; |
| | | //点击 |
| | | Win32Util::click(x,y,10); |
| | | if (win <= 0) { |
| | | //判断是否已经打开了同花顺远航版 |
| | | for (int i = 0; i < 10; i++) |
| | | { |
| | | win = THSActionUtil::getTradeSimpleDelegateWindow(); |
| | | if (win <= 0) |
| | | { |
| | | list<HWND> wlist = Win32Util::searchWindow("同花顺远航版"); |
| | | if (wlist.size() > 0) { |
| | | HWND mainWin = *(wlist.begin()); |
| | | //按F12 |
| | | Win32Util::sendMessage(mainWin, WM_KEYDOWN, VK_F12, 0); |
| | | Win32Util::sendMessage(mainWin, WM_KEYUP, VK_F12, 0); |
| | | //等待反应 |
| | | Sleep(500); |
| | | } |
| | | else { |
| | | //等待远航版打开 |
| | | Sleep(1000); |
| | | } |
| | | } |
| | | else { |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | | catch (...) { |
| | | |
| | | } |
| | | } |
| | | |
| | | //如果已经打开了远航版的交易,就需要点击当日委托 |
| | | try { |
| | | tradeListCapture->selectTradeSimpleDelegate(MatOcr); |
| | | } |
| | | catch (...) { |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | |
| | | tradeListCapture->startTradeDelegate(); |
| | | delegateBtn.SetWindowTextW(_T("暂停委托识别任务")); |
| | | } |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | //测试按钮 |
| | | void CappDlg::OnBnClickedButtonTest() |
| | | { |
| | | cv::Mat mat = cv::imread("C:\\Users\\Administrator\\Desktop\\ocr\\trade\\Snipaste_2023-01-13_18-23-34_gray.png", cv::IMREAD_GRAYSCALE); |
| | | Json::Value array; |
| | | int len = mat.rows * mat.cols; |
| | | for (int i = 0; i < len; i++) { |
| | | array[i] = mat.data[i]; |
| | | } |
| | | Json::Value data; |
| | | data["data"] = array; |
| | | data["width"] = mat.cols; |
| | | data["height"] = mat.rows; |
| | | data["key"] = "当日委托" ; |
| | | Json::Value root; |
| | | root["data"] = data; |
| | | root["type"] = 100; |
| | | string result = JsonUtil::jsonValue2String(root); |
| | | try { |
| | | socketManager->sendMsg(result.c_str()); |
| | | } |
| | | catch (string st) { |
| | | if (1 > 0) { |
| | | //THSActionUtil::correctL2ScreenPlate(MatOcr); |
| | | //如果已经打开了远航版的交易,就需要点击当日委托 |
| | | try { |
| | | THSActionUtil::correctL2ScreenPlate(OcrUtil::mat_ocr); |
| | | } |
| | | catch (...) { |
| | | |
| | | } |
| | | return; |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | |
| | | try { |
| | | THSActionUtil::checkEnv(); |
| | | checkTHSEnv(this); |
| | | } |
| | | catch (string e) { |
| | | //打开同花顺的所有屏幕 |
| | | try { |
| | | THSActionUtil::openL2Screen(); |
| | | THSActionUtil::openSecondScreen(); |
| | | Sleep(1000); |
| | | THSActionUtil::openThirdScreen(); |
| | | Sleep(1000); |
| | | } |
| | | catch (...) { |
| | | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | try { |
| | | HWND l2 = THSActionUtil::getL2Win(); |
| | | if (l2 > 0) |
| | | { |
| | | Win32Util::showWindow(l2); |
| | | //初始化l2的各个窗口句柄 |
| | | capture->refreshHWND(); |
| | | } |
| | | |
| | | HWND second = THSActionUtil::getSecondWindow(); |
| | | if (second <= 0) { |
| | | AfxMessageBox(_T("同花顺副屏1未打开")); |
| | | return; |
| | | } |
| | | |
| | | Win32Util::showWindow(second); |
| | | |
| | | |
| | | HWND third = THSActionUtil::getThirdWindow(); |
| | | if (third <= 0) { |
| | | AfxMessageBox(_T("同花顺副屏2未打开")); |
| | | return; |
| | | } |
| | | |
| | | Win32Util::showWindow(third); |
| | | |
| | | |
| | | //设置 |
| | | DEVMODE device = Win32Util::getL2ScreenInfo(); |
| | | int device_width = device.dmPelsWidth; |
| | | int device_height = device.dmPelsHeight; |
| | | POINTL device_pos = device.dmPosition; |
| | | //最大化L2 |
| | | Win32Util::moveWin(l2, device_pos.x, device_pos.y, device_width, device_height); |
| | | //将副屏1与副屏2缩小为屏幕的一半 |
| | | Win32Util::moveWin(second, device_pos.x, device_pos.y + device_height / 2, device_width / 2 - 50, device_height / 2); |
| | | Win32Util::moveWin(third, device_pos.x + device_width / 2 + 30, device_pos.y + device_height / 2, device_width / 2 - 50, device_height / 2); |
| | | } |
| | | catch (string e) { |
| | | CString msg(e.c_str()); |
| | | catch (string st) { |
| | | CString msg(st.c_str()); |
| | | AfxMessageBox(msg); |
| | | return; |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | |
| | | static string OnActionProcess(string data, void* context); |
| | | static string OnActionCallback(string data, void* context); |
| | | static string OnActionCallbackQueue(string data, void* context); |
| | | // 图像识别回调 |
| | | static list<OCRResult> MatOcr(string key_regex, cv::Mat mat); |
| | | |
| | | |
| | | |