admin
2023-02-09 125db633619a0b4c7bd1d498ea2bf1cefa4f73d3
'远程OCR'
23个文件已修改
2个文件已添加
1399 ■■■■ 已修改文件
ConsoleApplication/CaptureUtil.cpp 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/CaptureUtil.h 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/ImgUtil.cpp 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/ImgUtil.h 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/L2DataCapture.cpp 280 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/L2DataCapture.h 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/L2TradeQueueUtil.cpp 238 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/L2TradeQueueUtil.h 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/LimitUpCapture.cpp 68 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/LimitUpCapture.h 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/OpenCLExcuter.cpp 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/THSActionUtil.cpp 219 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/THSActionUtil.h 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/TradeListCapture.cpp 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/TradeListCapture.h 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/main.cpp 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/JsonUtil.h 66 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/OcrUtil.cpp 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/OcrUtil.h 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/SocketManager.cpp 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/SocketManager.h 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/app.vcxproj 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/app.vcxproj.filters 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/appDlg.cpp 200 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/appDlg.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/CaptureUtil.cpp
@@ -1,4 +1,5 @@
#include "CaptureUtil.h"
#include "Win32Util.h"
HWND CaptureUtil::level2Frames[8];
HWND CaptureUtil::tradeQueueFrames[8];
@@ -57,7 +58,7 @@
        }
        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);
            }
ConsoleApplication/CaptureUtil.h
@@ -9,7 +9,7 @@
using namespace std;
enum CaptureContentType {
    CAPTURE_TYPE_L2,
    CAPTURE_TYPE_TRADE_QUEUE
    CAPTURE_TYPE_TRADE_QUEUE,
};
struct FrameInfo
{
ConsoleApplication/ImgUtil.cpp
@@ -1074,3 +1074,31 @@
    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;
}
ConsoleApplication/ImgUtil.h
@@ -66,6 +66,14 @@
    int endy;
};
struct  OCRResult
{
    string text;
    RECT rect;
};
using namespace std;
class ImgUtil
{
@@ -125,6 +133,9 @@
    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);
};
ConsoleApplication/L2DataCapture.cpp
@@ -7,6 +7,7 @@
#include "GPUtil.h"
#include "LogUtil.h"
#include "L2TradeQueueUtil.h"
#include "Win32Util.h"
//#define malloc(size) malloc(size)
//#define free(ptr) free(ptr)
@@ -38,6 +39,8 @@
void L2DataCapture::_run(int index)
{
    while (true) {
        clock_t origin_start_time = clock();
        if (killRunnings[index])
            break;
        TaskChecker::clientLiveTime.l2[index] = clock();
@@ -53,23 +56,39 @@
        }
        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]);
@@ -88,6 +107,14 @@
            }
        }
        Sleep(2);
        if (index == 0)
        {
            cout << "-----------整个L2周期时间消耗时间消耗:-------------  " << index << "  " << clock() - origin_start_time << endl;
        }
        if (index == 0)
        {
            cout << "-----------------------结束-------------------- \n\n " << endl;
        }
    }
}
@@ -114,17 +141,10 @@
            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 (...) {
@@ -133,6 +153,138 @@
        }
        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) {
@@ -255,7 +407,7 @@
    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;
}
@@ -263,6 +415,7 @@
list<TradeData*> L2DataCapture::captureLevel2TradeData(OpenCLExcuter* openCLExcuter, cv::Mat& oimg, int identify)
{
    bool ENABLE_LOG = FALSE;
    if (oimg.cols <= 0 || oimg.rows <= 0) {
        throw string("图像数据错误");
@@ -300,7 +453,7 @@
        }
        //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;
@@ -389,7 +542,7 @@
    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;
    //结果初始化
@@ -458,7 +611,7 @@
    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;
@@ -470,7 +623,7 @@
    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());
@@ -517,7 +670,7 @@
    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);
@@ -529,7 +682,7 @@
    }
    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);
@@ -555,7 +708,7 @@
    */
    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;
    //准备模板数字
@@ -572,11 +725,11 @@
    //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;
@@ -647,7 +800,7 @@
    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;
    //释放内存
@@ -660,47 +813,66 @@
L2TradeQueue L2DataCapture::captureLevel2TradeQueueData(HWND hwnd, int index)
{
    HWND buyQueueHWND = L2TradeQueueUtil::getTradeQueueBuyHWND(hwnd);
    //获取位置
    RECT prect;
    Win32Util::getWindowRect(hwnd, &prect);
    RECT buyRect;
    Win32Util::getWindowRect(buyQueueHWND, &buyRect);
    cv::Mat mat =    CaptureUtil::capture(hwnd);
    return captureLevel2TradeQueueData(mat,index);
    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;
    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];
    }
    else {
    }
    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 {
            if (oimg.channels() == 3)
            {
                openCLExcuter->rgb2Gray(oimg, img.data);
            }
            else {
                openCLExcuter->rgba2Gray(oimg, img.data);
            }
            oimg.release();
        std::list<string> buyQueueList = captureLevel2TradeQueueBuyData(openCLExcuter, buyQueueImg, identify);
        tradeQueue.buyQueue = buyQueueList;
        }
        catch (...) {
            oimg.release();
            oimg = NULL;
            img.release();
            img = NULL;
            throw string("灰度出错");
        }
    free(datas);
    return tradeQueue;
    }
L2TradeQueue L2DataCapture::captureLevel2TradeQueueViewData(OpenCLExcuter* openCLExcuter, cv::Mat& img, int identify)
{
    L2TradeQueue tradeQueue;
    try {
        list<ImgArea> splitAreas = L2TradeQueueUtil::splitElements(img);
        int* splitResult = (int*)malloc(sizeof(int) * 4 * 6);
        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;
@@ -730,12 +902,13 @@
            }
        }
        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);
@@ -824,7 +997,7 @@
        free(numberResult);
    
        L2TradeQueue tradeQueue = L2TradeQueue();
        tradeQueue = L2TradeQueue();
        tradeQueue.buyOnePrice = buyOnePrice;
        tradeQueue.buyOneVolumn = buyOneNum;
        tradeQueue.buyTime = buyOneTime;
@@ -838,7 +1011,6 @@
        img = NULL;
        throw int(ERROR_CODE_DIVIDE_IMG_FAIL);
    }
}
//捕获level2的盘口数据
ConsoleApplication/L2DataCapture.h
@@ -16,6 +16,8 @@
    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);
@@ -51,6 +53,11 @@
    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:
@@ -92,9 +99,10 @@
    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);
ConsoleApplication/L2TradeQueueUtil.cpp
@@ -1,6 +1,8 @@
#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);
@@ -74,7 +76,7 @@
    freeData(dataList);
    free(rowData);
    if (false) {
    if (FALSE) {
        //保存
        int index = -1;
        for (list<ImgArea>::iterator ele = posList.begin(); ele != posList.end(); ++ele) {
@@ -93,6 +95,216 @@
    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;
@@ -129,23 +341,25 @@
    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;
@@ -167,6 +381,16 @@
            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;
}
ConsoleApplication/L2TradeQueueUtil.h
@@ -6,12 +6,21 @@
    //行分隔
    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);
};
ConsoleApplication/LimitUpCapture.cpp
@@ -13,6 +13,7 @@
bool LimitUpCapture::kill;
CallbackFun_Limit_Up LimitUpCapture::data_callback;
MatOcrFun  LimitUpCapture::ocr_fun;
std::list<cv::Point> LimitUpCapture::pointList;
@@ -45,7 +46,7 @@
            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();
            }
@@ -62,8 +63,9 @@
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;
@@ -136,63 +138,19 @@
        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;
    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);
            }
        }
        else {
            if (full_start >= 0)
            {
                if (start_row < 0)
                {
                    start_row = r;
                    end_row = r;
                }
                else {
                    end_row = r;
                }
            }
        }
    }
    //cv::imwrite("C:\\Users\\Administrator\\Desktop\\ocr\\menu.jpg", );
    //保存临时图片
    //cv::imwrite("C:\\Users\\Administrator\\Desktop\\ocr\\menu.jpg", grayImg);
}
bool LimitUpCapture::isRunning() {
ConsoleApplication/LimitUpCapture.h
@@ -37,6 +37,8 @@
    static CallbackFun_Limit_Up data_callback;
    static MatOcrFun  ocr_fun;
    static void* context;
    static void _run();
@@ -58,7 +60,7 @@
    //是否暂停
    static bool pause;
    void init(CallbackFun_Limit_Up callback, void* context);
    void init(CallbackFun_Limit_Up callback, MatOcrFun matMcrFun, void* context);
    //重新创建运行线程
    void reCreateRunning();
ConsoleApplication/OpenCLExcuter.cpp
@@ -517,7 +517,7 @@
    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) {
@@ -619,7 +619,7 @@
        excuteError();
        throw st;
    }
    std::cout << " 耗时:" << (clock() - time_0) << std::endl;
    //std::cout << " 耗时:" << (clock() - time_0) << std::endl;
}
@@ -726,7 +726,7 @@
    
    std::cout << " 耗时:" << (clock() - time_0) << std::endl;
    //std::cout << " 耗时:" << (clock() - time_0) << std::endl;
}
@@ -841,7 +841,7 @@
    
    std::cout << " 耗时:" << (clock() - time_0) << std::endl;
    //std::cout << " 耗时:" << (clock() - time_0) << std::endl;
}
@@ -933,7 +933,7 @@
        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);
@@ -1479,6 +1479,11 @@
        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);
ConsoleApplication/THSActionUtil.cpp
@@ -56,6 +56,125 @@
    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("同花顺(");
@@ -165,12 +284,29 @@
        if (isL2Screen(str)) {
            //判断内容是否为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("同花顺(");
@@ -228,6 +364,86 @@
            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() {
@@ -1042,6 +1258,8 @@
}
//分隔L2数据的目录
std::list<GPCodeArea> splitL2Cate(cv::Mat img) {
    int cols = img.cols;
@@ -1168,7 +1386,6 @@
    }
    return areaList;
}
//分隔L2交易队列
ConsoleApplication/THSActionUtil.h
@@ -31,6 +31,7 @@
    //L2数据有效
    int cateIndex;
};
typedef list<OCRResult> (*MatOcrFun)(string key_regex,cv::Mat mat);
//同花顺事件
class THSActionUtil
{
@@ -77,6 +78,8 @@
    //打开同花顺的副屏幕
    static void openL2Screen();
    //矫正L2代码板块(选中首版待选)
    static bool correctL2ScreenPlate(MatOcrFun matOcrFun);
    static void openSecondScreen();
    static void openThirdScreen();
    static void openTradeSuccessScreen();
ConsoleApplication/TradeListCapture.cpp
@@ -45,7 +45,7 @@
            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();
            }
@@ -77,7 +77,7 @@
            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();
            }
@@ -158,6 +158,60 @@
}
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()
{
    kill_s = TRUE;
ConsoleApplication/TradeListCapture.h
@@ -92,6 +92,12 @@
    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();
ConsoleApplication/main.cpp
@@ -157,7 +157,7 @@
    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)
    {
@@ -172,14 +172,16 @@
    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() {
@@ -187,8 +189,8 @@
    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");
}
@@ -218,9 +220,15 @@
    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) {
app/JsonUtil.h
@@ -47,6 +47,7 @@
    //json对象转为字符串
    static  std::string toJsonStr(Json::Value json) {
        clock_t start_time = clock();
        Json::StreamWriterBuilder writerBuilder;
        //不自动换行
        writerBuilder.settings_["indentation"] = "";
@@ -55,22 +56,51 @@
        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;
    }
@@ -86,6 +116,13 @@
        _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;
@@ -350,6 +387,11 @@
        return root;
    }
    static string jsonValue2String(Json::Value value) {
        Json::FastWriter fastWriter;
        std::string output = fastWriter.write(value);
app/OcrUtil.cpp
New file
@@ -0,0 +1,67 @@
#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("识别失败");
}
app/OcrUtil.h
New file
@@ -0,0 +1,42 @@
#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);
};
app/SocketManager.cpp
@@ -228,3 +228,30 @@
    }
    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);
}
app/SocketManager.h
@@ -26,6 +26,7 @@
    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);
@@ -60,6 +61,8 @@
    static string sendMsg(const char*);
    static string sendOcrMsg(const char*);
};
app/app.vcxproj
@@ -217,6 +217,7 @@
    <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" />
@@ -237,6 +238,7 @@
    <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>
app/app.vcxproj.filters
@@ -108,6 +108,9 @@
    <ClInclude Include="StringUtils.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="OcrUtil.h">
      <Filter>头文件</Filter>
    </ClInclude>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="app.cpp">
@@ -155,6 +158,9 @@
    <ClCompile Include="StringUtils.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="OcrUtil.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="app.rc">
app/appDlg.cpp
@@ -16,6 +16,7 @@
#endif 
#include "JsonUtil.h"
#include <exception>
#include "OcrUtil.h"
#ifdef _DEBUG
@@ -481,18 +482,29 @@
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) {
            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());
        }
@@ -501,7 +513,10 @@
            app->socketManager->resetClient(index);
            app->socketManager->Connect(index);
        }
        //cout << "*****数据处理时间:" << (clock() - time_start) << endl;
        if (index == 0)
        {
            cout << "\n*****服务端数据处理时间*****:" << (clock() - time_start) << endl;
        }
    }
}
@@ -583,23 +598,19 @@
        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;
@@ -1042,6 +1053,11 @@
    return string();
}
list<OCRResult> CappDlg::MatOcr(string key_regex, cv::Mat mat)
{
    return OcrUtil::mat_ocr(key_regex, mat);
}
//心跳信号
void  CappDlg::onHeartbeat() {
    //5s一次心跳
@@ -1115,7 +1131,7 @@
    if (!limitUpCapture->isInited())
    {
        try {
            limitUpCapture->init(OnLimitUpDataCallback, this);
            limitUpCapture->init(OnLimitUpDataCallback,  MatOcr, this);
        }
        catch (string st) {
            if (notify)
@@ -1185,6 +1201,13 @@
        Win32Util::showWindow(l2);
        //初始化l2的各个窗口句柄
        app->capture->refreshHWND();
        //选中板块
        try {
            //THSActionUtil::correctL2ScreenPlate(OcrUtil::mat_ocr);
        }
        catch (string st) {
        }
    }
    HWND  second = THSActionUtil::getSecondWindow();
@@ -1213,6 +1236,14 @@
    //将副屏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)
@@ -1446,7 +1477,7 @@
void CappDlg::OnBnClickedButton20()
{
    try {
        THSActionUtil::checkEnv();
        checkTHSEnv(this);
        AfxMessageBox(_T("检测通过"));
    }
    catch (const string& st) {
@@ -1459,16 +1490,6 @@
//启动任务
void CappDlg::OnBnClickedButton5()
{
    //检测环境
    try {
        THSActionUtil::checkEnv();
    }
    catch (string st) {
        CString msg(st.c_str());
        AfxMessageBox(msg);
        return;
    }
    CButton* btn = (CButton*)GetDlgItem(IDC_BUTTON5);
@@ -1484,6 +1505,9 @@
        }
    }
    if (!capture->isRunning()) {
        // 检测环境
        checkTHSEnv(this);
        try {
            map<int, string> result = THSActionUtil::getListenL2GPCodes(recognitionManager);
@@ -1513,6 +1537,14 @@
        //TODO 测试图片切割
        //THSActionUtil::getListenL2GPAreaActionBar();
        // 检测同花顺板块是否选中
        try {
            Sleep(500);
            THSActionUtil::correctL2ScreenPlate(OcrUtil::mat_ocr);
        }
        catch (...) {
        }
    }
    else {
@@ -1655,7 +1687,7 @@
    if (!limitUpCapture->isInited()) {
        try
        {
            limitUpCapture->init(OnLimitUpDataCallback, this);
            limitUpCapture->init(OnLimitUpDataCallback,MatOcr,this);
        }
        catch (string st)
@@ -1725,6 +1757,13 @@
            CString msg(st.c_str());
            AfxMessageBox(msg);
            return;
        }
        //如果已经打开了远航版的交易,就需要点击当日委托
        try {
            tradeListCapture->selectTradeSuccess(MatOcr);
        }
        catch (...) {
        }
        tradeListCapture->startTradeSuccess();
@@ -1807,29 +1846,7 @@
   //如果已经打开了远航版的交易,就需要点击当日委托
   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);
        }
      }
        tradeListCapture->selectTradeSimpleDelegate(MatOcr);
   }
   catch (...) {
   
@@ -1871,33 +1888,24 @@
        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);
    if (1 > 0) {
        //THSActionUtil::correctL2ScreenPlate(MatOcr);
        //如果已经打开了远航版的交易,就需要点击当日委托
    try {
        socketManager->sendMsg(result.c_str());
            THSActionUtil::correctL2ScreenPlate(OcrUtil::mat_ocr);
    }
    catch (string st) {
        catch (...) {
        }
        return;
    }
}
@@ -1912,67 +1920,13 @@
{
    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;
    }
}
app/appDlg.h
@@ -57,6 +57,8 @@
    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);