admin
2022-07-07 30f434d78b58e3a4198cf5ba5a9e5a0ce1cd5292
'bug修复'
26个文件已修改
3个文件已添加
1383 ■■■■ 已修改文件
ConsoleApplication/ImgUtil.cpp 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/ImgUtil.h 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/OpenCLExcuter.cpp 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/RecognitionManager.h 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/ScreenDataCapture.cpp 93 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/ScreenDataCapture.h 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/THSActionUtil.cpp 124 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/THSActionUtil.h 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/Win32Util.cpp 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/kernel.cl 227 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/ExcelUtil.cpp 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/GUITool.cpp 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/GUITool.h 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/JsonUtil.h 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/SocketManager.cpp 58 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/SocketManager.h 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/app.aps 补丁 | 查看 | 原始文档 | blame | 历史
app/app.rc 补丁 | 查看 | 原始文档 | blame | 历史
app/app.vcxproj 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/app.vcxproj.filters 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/appDlg.cpp 164 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/appDlg.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/codesDataDlog.cpp 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/codesDataDlog.h 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/kernel.cl 217 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/level2DataDlg.cpp 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/level2DataDlg.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/resource.h 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/tool.h 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ConsoleApplication/ImgUtil.cpp
@@ -279,6 +279,14 @@
        }
    }
    if (startRow < 0) {
        throw string("数字分隔未查找到起始行");
    }
    if (endRow < 0) {
        throw string("数字分隔未查找到结束行");
    }
    binary = cv::Mat(binary, cv::Rect(0, startRow, cols, endRow - startRow + 1));
    rows = binary.rows;
    cols = binary.cols;
@@ -927,7 +935,15 @@
cv::Mat ImgUtil::grayImage(cv::Mat src) {
    cv::Mat grayImage;
    cvtColor(src, grayImage, cv::COLOR_RGB2GRAY);
    if (src.channels() == 3)
    {
        cvtColor(src, grayImage, cv::COLOR_RGB2GRAY);
    }else if (src.channels() == 4) {
        cvtColor(src, grayImage, cv::COLOR_RGBA2GRAY);
    }
    else if (src.channels() == 1) {
        return src;
    }
    return grayImage;
}
ConsoleApplication/ImgUtil.h
@@ -28,16 +28,16 @@
#endif 
#ifndef _NUMBER_L2_TOTAL_NUMBER
#define _NUMBER_L2_TOTAL_NUMBER 17
#define _NUMBER_L2_TOTAL_NUMBER 19
#endif 
#ifndef _NUMBER_GP_CODE_WIDTH
#define _NUMBER_GP_CODE_WIDTH 12
#define _NUMBER_GP_CODE_WIDTH 6
#endif 
#ifndef _NUMBER_GP_CODE_HEIGHT
#define _NUMBER_GP_CODE_HEIGHT 14
#define _NUMBER_GP_CODE_HEIGHT 10
#endif 
#ifndef _NUMBER_GP_CODE_TOTAL_NUMBER
ConsoleApplication/OpenCLExcuter.cpp
@@ -18,7 +18,7 @@
        throw("Creat context failed!");
    }
    //创建程序;注意要用"rb"
    fopen_s(&program_handle, "kernel.cl", "rb");
    fopen_s(&program_handle, "D:\\workspace\\CPlusTest\\ConsoleApplication\\ConsoleApplication\\kernel.cl", "rb");
    if (program_handle == NULL) {
        throw("The kernle can not be opened!");
    }
@@ -222,7 +222,7 @@
    int inputSize = (img_width * img_height);
    int resultSize = (pos_count / 3) * (num_count * num_width * num_height * 10);
    int resultSize = (pos_count / 4) * (num_count * num_width * num_height * 10);
    //创建缓存对象
@@ -437,7 +437,7 @@
    int inputSize = imgWidth * imgHeight;
    int resultSize = lines * 2;
    int resultSize = lines * 3;
    //创建缓存对象
ConsoleApplication/RecognitionManager.h
@@ -20,14 +20,23 @@
    LIMIT_PRICE_DOWN,
};
enum CANCEL_TIME_UNIT {
    TIME_SECOND,
    TIME_MINITE,
    TIME_HOUR,
};
struct TradeData
{
    //排序值
    int index;
    //时间
    string time;
    //买撤时间
    string buyCancelTime;
    int cancelTime;
    CANCEL_TIME_UNIT cancelTimeUnit;
    //价格
    string price;
    //是否为涨停价
ConsoleApplication/ScreenDataCapture.cpp
@@ -24,8 +24,13 @@
            latest_running_times[index] = clock();
            //识别数据
            string code = gpCodes[index];
            list<TradeData> resultList=captureLevel2TradeData(CaptureUtil::capture(index), index);
            data_callback(index,code, resultList, context);
            try {
                list<TradeData> resultList = captureLevel2TradeData(CaptureUtil::capture(index), index);
                data_callback(index, code, resultList, context);
            }
            catch (...) {
            }
        }
        Sleep(2);
    }
@@ -173,11 +178,11 @@
    try {
        rowDataList = ImgUtil::divideImg(img);
        if (rowDataList.size() == 0) {
            throw ERROR_CODE_DIVIDE_IMG_FAIL;
            throw int(ERROR_CODE_DIVIDE_IMG_FAIL);
        }
    }
    catch (...) {
        throw ERROR_CODE_DIVIDE_IMG_FAIL;
        throw int(ERROR_CODE_DIVIDE_IMG_FAIL);
    }
    //准备数据
    int* rowDataOneLevel = (int*)malloc(sizeof(int) * rowDataList.size() * 4);
@@ -196,6 +201,37 @@
    int* rowSplitDataOneLevel = (int*)malloc(sizeof(int) * rowDataList.size() * 4 * 7);
    openCLExcuter[identify]->splitL2RowData(imgData, img.cols, img.rows, rowDataOneLevel, rowDataList.size(), rowSplitDataOneLevel);
    free(rowDataOneLevel);
    /*
    for (int i = 0;i < rowDataList.size();i++) {
        string path = "C:\\Users\\Administrator\\Desktop\\ocr\\cancel_time\\";
        path.append(to_string(identify)).append("_").append(to_string(i)).append(".jpg");
        int start = 4 * 7 * i;
        start += 4 * (1);
        int startx = rowSplitDataOneLevel[start];
        int starty = rowSplitDataOneLevel[start + 1];
        int endx = rowSplitDataOneLevel[start + 2];
        int endy = rowSplitDataOneLevel[start + 3];
        if (startx > 0) {
            cv::imwrite(path, cv::Mat(img, cv::Rect(startx, starty, endx - startx + 1, endy - starty + 1)));
        }
    }
    */
    /*
    //保存分隔的图片
    if (true) {
        int start = 4 * 7 * (558 - 1);
        start += 4 * (2);
        int startx=    rowSplitDataOneLevel[start];
        int starty = rowSplitDataOneLevel[start+1];
        int endx = rowSplitDataOneLevel[start+2];
        int endy = rowSplitDataOneLevel[start+3];
        cv::imshow("价格", cv::Mat(img, cv::Rect(startx, starty, endx - startx + 1, endy - starty + 1)));
    }
    */
    clock_t time_3 = clock();
@@ -219,7 +255,7 @@
    clock_t time_31 = clock();
    std::cout << "数据准备-图像数据准备: threadid-" << std::this_thread::get_id() << " 耗时:" << time_31 - time_3 << endl;
    int* pos = (int*)malloc(sizeof(int) * 3 * 4 * rowDataList.size());
    int* pos = (int*)malloc(sizeof(int) * 4 * 4 * rowDataList.size());
    index = 0;
@@ -228,14 +264,21 @@
        int startS = index * 4 * 7;
        int start = index * 4 * 3;
        int start = index * 4 * 4;
        pos[start] = rowSplitDataOneLevel[startS + 0];
        pos[start + 1] = rowSplitDataOneLevel[startS + 1];
        pos[start + 2] = rowSplitDataOneLevel[startS + 2];
        pos[start + 3] = rowSplitDataOneLevel[startS + 3];
        start = index * 4 * 3 + 4 * 1;
        start = index * 4 * 4 + 4 * 1;
        pos[start] = rowSplitDataOneLevel[startS + 4 * 1 + 0];
        pos[start + 1] = rowSplitDataOneLevel[startS + 4 * 1 + 1];
        pos[start + 2] = rowSplitDataOneLevel[startS + 4 * 1 + 2];
        pos[start + 3] = rowSplitDataOneLevel[startS + 4 * 1 + 3];
        start = index * 4 * 4 + 4 * 2;
        pos[start] = rowSplitDataOneLevel[startS + 4 * 2 + 0];
        pos[start + 1] = rowSplitDataOneLevel[startS + 4 * 2 + 1];
        pos[start + 2] = rowSplitDataOneLevel[startS + 4 * 2 + 2];
@@ -243,7 +286,7 @@
        start = index * 4 * 3 + 4 * 2;
        start = index * 4 * 4 + 4 * 3;
        pos[start] = rowSplitDataOneLevel[startS + 4 * 5 + 0];
        pos[start + 1] = rowSplitDataOneLevel[startS + 4 * 5 + 1];
        pos[start + 2] = rowSplitDataOneLevel[startS + 4 * 5 + 2];
@@ -267,7 +310,7 @@
    clock_t time_33 = clock();
    std::cout << "数据准备-0数据准备: threadid-" << std::this_thread::get_id() << " 耗时:" << time_33 - time_32 << endl;
    openCLExcuter[identify]->splitL2Num(imgData, img.cols, img.rows, pos, 3 * rowDataList.size(), zeroData, _NUMBER_L2_WIDTH, _NUMBER_L2_HEIGHT, _NUMBER_L2_TOTAL_NUMBER, totalNumberData);
    openCLExcuter[identify]->splitL2Num(imgData, img.cols, img.rows, pos, 4 * rowDataList.size(), zeroData, _NUMBER_L2_WIDTH, _NUMBER_L2_HEIGHT, _NUMBER_L2_TOTAL_NUMBER, totalNumberData);
    free(pos);
    free(zeroData);
@@ -302,14 +345,28 @@
    list<TradeData> resultList;
    int* notNumberResult = (int*)malloc(sizeof(int)* rowDataList.size()*2);
    int* notNumberResult = (int*)malloc(sizeof(int)* rowDataList.size()*3);
    openCLExcuter[identify]->recognitionNotNum(img.data,img.cols,img.rows, rowSplitDataOneLevel,7, rowDataList.size(), notNumberResult);
    for (int i = 0;i < rowDataList.size();i++) {
        TradeData td = TradeData();
        switch (notNumberResult[i * 2])
        switch (notNumberResult[i * 3])
        {
        case 0:
            td.cancelTimeUnit = TIME_SECOND;break;
        case 1:
            td.cancelTimeUnit = TIME_MINITE;break;
        case 2:
            td.cancelTimeUnit = TIME_HOUR;break;
        default:
            break;
        }
        switch (notNumberResult[i * 3+1])
        {
        case 0:
            td.limitPrice = LIMIT_PRICE_NORMAL;break;
@@ -321,7 +378,7 @@
        default:
            break;
        }
        switch (notNumberResult[i * 2 + 1])
        switch (notNumberResult[i * 3 + 2])
        {
        case OPERATE_BUY:
            td.operateType = OPERATE_BUY;
@@ -373,19 +430,25 @@
        time.append(to_string(lineData[2])).append(to_string(lineData[3]));
        time.append(":");
        time.append(to_string(lineData[4])).append(to_string(lineData[5]));
        string cancelTime = "";
        cancelTime.append(to_string(lineData[6])).append(to_string(lineData[7]));
        string price = "";
        price.append(to_string(lineData[6])).append(to_string(lineData[7])).append(to_string(lineData[8])).append(to_string(lineData[9]));
        price.append(to_string(lineData[6+2])).append(to_string(lineData[7+2])).append(to_string(lineData[8+2])).append(to_string(lineData[9+2]));
        price.append(".");
        price.append(to_string(lineData[10])).append(to_string(lineData[11]));
        price.append(to_string(lineData[10+2])).append(to_string(lineData[11+2]));
        string num = "";
        num.append(to_string(lineData[12])).append(to_string(lineData[13])).append(to_string(lineData[14])).append(to_string(lineData[15])).append(to_string(lineData[16]));
        num.append(to_string(lineData[12+2])).append(to_string(lineData[13+2])).append(to_string(lineData[14+2])).append(to_string(lineData[15+2])).append(to_string(lineData[16+2]));
        (*tradeEle).time = time;
        (*tradeEle).num = stoi(num);
        (*tradeEle).price = price;
        (*tradeEle).index = index;
        (*tradeEle).cancelTime = stoi(cancelTime);
        //释放内存
        free(lineData);
ConsoleApplication/ScreenDataCapture.h
@@ -4,7 +4,7 @@
#include <map> 
#include "OpenCLExcuter.h"
#include "CaptureUtil.h"
#define THS_FRAME_COUNT 1
#define THS_FRAME_COUNT 8
typedef void (*CallbackFun)(int index, string code, list<TradeData> dataList, void* contex);
ConsoleApplication/THSActionUtil.cpp
@@ -20,6 +20,29 @@
    return    str.find("同花顺(") != string::npos && str.find("副屏") != string::npos;
}
std::list<cv::Mat> splitGPCodeNum(cv::Mat img) {
    std::list<cv::Mat> nums = ImgUtil::splitNum(img, 96);
    if (nums.size() != 6) {
        int retryCount = 0;
        while (retryCount < 4) {
            retryCount++;
            nums = ImgUtil::splitNum(img, 96 + retryCount * 10);
            if (nums.size() == 6) {
                break;
            }
        }
    }
    if (nums.size() != 6) {
        std::string path = "C:\\Users\\Administrator\\Desktop\\ocr\\gpcode\\";
        path.append(std::to_string(rand())).append("_listen.jpg");
        imwrite(path, img);
        throw string("代码数字分隔出错");
    }
    return    nums;
}
//获取副屏
HWND getSecondWindow() {
    list<HWND> wlist = Win32Util::searchWindow("同花顺(");
@@ -116,7 +139,7 @@
    if (!open) {
        if (mainPage <= 0) {
            throw("未找到首页");
            throw string("未找到首页");
        }
        Win32Util::focus(mainPage);
@@ -156,13 +179,17 @@
        sw = getSecondWindow();
    }
    if (sw <= 0) {
        throw("未打开副屏");
        throw string("未打开副屏");
    }
    Win32Util::focus(sw);
    //打开板块
    Win32Util::keyboardNum(quickCode, 100);
    Win32Util::keyboard(VK_RETURN, 200);
    //打开板块
    RECT rect;
    GetWindowRect(sw, &rect);
    Win32Util::mouseMove(rect.left + 10, rect.top + 5, 1);
    //Win32Util::click(10);
    Win32Util::focus(sw);
    Win32Util::keyboardNum(quickCode, 200);
    Win32Util::keyboard(VK_RETURN, 1000);
    Sleep(2000);
    //设置板块中的股票
@@ -208,7 +235,6 @@
    //获取内容板块坐标
    RECT rect;
    GetWindowRect(sw, &rect);
    Win32Util::mouseMove(rect.left + 10, rect.top + 5, 1);
    Win32Util::click(10);
@@ -230,13 +256,16 @@
    //----增加
    //截图,识别出增加按钮位置,点击增加,输入内容
    for (std::list<string>::iterator ele = tempCodeList.begin();ele != tempCodeList.end();++ele) {
        addGP(*ele);
        Sleep(100);
        if ((*ele).length() > 0)
        {
            addGP(*ele);
            Sleep(100);
        }
    }
    oimg = CaptureUtil::capture(content);
    if (oimg.cols <= 0 || oimg.rows <= 0) {
        throw("板块截屏内容为空");
        throw string("板块截屏内容为空");
    }
    img = ImgUtil::grayImage(oimg);
    areaList = recognitionGPArea(img);
@@ -273,14 +302,14 @@
        sw = getSecondWindow();
    }
    if (sw <= 0) {
        throw("未打开副屏");
        throw string("未打开副屏");
    }
    HWND content = FindWindowExA(sw, NULL, "AfxFrameOrView100s", NULL);
    cv::Mat oimg = CaptureUtil::capture(content);
    cv::Mat img = ImgUtil::grayImage(oimg);
    if (img.cols <= 0 || img.rows <= 0) {
        throw("板块截屏内容为空");
        throw string("板块截屏内容为空");
    }
    std::list<GPCodeArea>  areaList = recognitionGPArea(img);
    for (std::list<GPCodeArea>::iterator ele = areaList.begin();ele != areaList.end();++ele) {
@@ -335,7 +364,7 @@
                break;
            }
            if (startf > -1 && endf > -1 && emptyEndRow - emptyStartRow > 4) {
            if (startf > -1 && endf > -1 && emptyEndRow - emptyStartRow > 3) {
                //内容坐标
                   //LogUtil::debug("内容的高度为:%d \n", endf - startf);
                int* dd = (int*)malloc(sizeof(int) * 4);
@@ -457,7 +486,11 @@
            area.starty = *(*ele + 1);
            area.endx = *(*ele + 2);
            area.endy = *(*ele + 3);
            resultList.push_back(area);
            //过滤
            if (area.endx - area.startx > 20)
            {
                resultList.push_back(area);
            }
        }
        else {
            std::list<int*>::iterator ele = rowDataList.begin();
@@ -522,7 +555,7 @@
    }
    if (contentStartRow < 0) {
        throw("起始行分隔出错");
        throw string("起始行分隔出错");
    }
    //分隔列
@@ -547,15 +580,20 @@
    }
    if (startC < 0 || endC < 0) {
        throw("内容框分隔出错");
        throw string("内容框分隔出错");
    }
    //cv::imshow("内容", cv::Mat(img, cv::Rect(startC, contentStartRow, endC - startC, rows - contentStartRow)));
    startC += 1;
    endC -= 1;
    std::list<GPCodeArea> resultList = splitGPCodeArea(img, contentStartRow + 30, startC, rows, endC);
    std::list<GPCodeArea> resultList;
    try {
        resultList = splitGPCodeArea(img, contentStartRow + 25, startC, rows, endC);
    }
    catch (...) {
        throw string("分隔代码区域出错");
    }
    return resultList;
}
std::list<GPCodeArea>   THSActionUtil::recognitionNum(cv::Mat img, std::list<GPCodeArea> areaList) {
@@ -581,8 +619,10 @@
                path.append(".jpg");
                cv::imwrite(path, nums);
            }
            std::list<cv::Mat> list2 = ImgUtil::splitNum(nums, 96);
            std::list<cv::Mat> list2 = splitGPCodeNum(nums);
            if (false) {
                std::list<cv::Mat>::iterator e;
                int ci = 0;
@@ -612,6 +652,18 @@
}
std::list<string> THSActionUtil::recognitionGPCode(cv::Mat img) {
    cv::Mat grayImg = ImgUtil::grayImage(img);
    std::list<GPCodeArea> areaList = recognitionGPArea(grayImg);
    std::list<GPCodeArea>  list = recognitionNum(grayImg, areaList);
    std::list<string> resultList;
    for (std::list<GPCodeArea>::iterator ele = list.begin();ele != list.end();ele++) {
        resultList.push_back((*ele).code);
    }
    return resultList;
}
//分隔L2数据的目录
std::list<GPCodeArea> splitL2Cate(cv::Mat img) {
    int cols = img.cols;
@@ -638,7 +690,7 @@
    }
    if (contentStartRow < 0 || contentEndRow < 0) {
        throw("起始行或结束行分隔出错");
        throw string("起始行或结束行分隔出错");
    }
    //分隔列
@@ -725,12 +777,12 @@
std::map<int,string> THSActionUtil::getListenL2GPCodes() {
std::map<int, string> THSActionUtil::getListenL2GPCodes() {
    std::list<GPCodeArea> areaList = getListenL2GP();
    std::map<int, string> map;
    for (std::list<GPCodeArea>::iterator ele = areaList.begin();ele != areaList.end();ele++) {
        GPCodeArea data = (*ele);
        if (map.count(data.cateIndex)==0&&data.type== IMG_TYPE_GP) {
        if (map.count(data.cateIndex) == 0 && data.type == IMG_TYPE_GP) {
            map[data.cateIndex] = data.code;
        }
    }
@@ -770,29 +822,29 @@
    //分隔图片
    std::list<GPCodeArea>  areaList = splitL2Cate(img);
    std::list<GPCodeArea> fresultList;
    int index = 0;
    for (std::list<GPCodeArea>::iterator ele = areaList.begin();ele != areaList.end();ele++) {
        GPCodeArea area = *ele;
        index++;
        std::list<GPCodeArea> resultList = splitGPCodeArea(img, area.starty + 20, area.startx, area.endy, area.endx);
        if (false) {
            std::string path = "C:\\Users\\Administrator\\Desktop\\ocr\\gpcode\\";
            path.append(std::to_string(index)).append("_listen.jpg");
            imwrite(path, cv::Mat(img, cv::Rect(area.startx, area.starty, area.endx - area.startx + 1, area.endy - area.starty + 1)));
        }
        for (std::list<GPCodeArea>::iterator ele1 = resultList.begin();ele1 != resultList.end();ele1++) {
            GPCodeArea areaC = *ele1;
            if (areaC.type == IMG_TYPE_GP) {
                list<cv::Mat> nums = ImgUtil::splitNum(cv::Mat(img, cv::Rect(areaC.startx, areaC.starty, areaC.endx - areaC.startx + 1, areaC.endy - areaC.starty + 1)), 96);
                cv::Mat src = cv::Mat(img, cv::Rect(areaC.startx, areaC.starty, areaC.endx - areaC.startx + 1, areaC.endy - areaC.starty + 1));
                if (false) {
                    string path = "C:\\Users\\Administrator\\Desktop\\ocr\\gpcode\\";
                    path.append(to_string(index)).append(".jpg");
                    cv::imwrite(path, src);
                }
                list<cv::Mat> nums = splitGPCodeNum(src);
                if (!recognitionManager) {
                    recognitionManager = new RecognitionManager();
                }
                if (nums.size() != 6) {
                    throw string("代码分隔出错");
                }
                list<uchar>  rresult = recognitionManager->recognitionGPCode(nums);
                string num;
@@ -800,13 +852,15 @@
                    num.append(to_string(*e));
                }
                (*ele1).code = num;
                (*ele1).cateIndex = index-1;
                (*ele1).cateIndex = index - 1;
                fresultList.push_back(*ele1);
            }
        }
        return resultList;
    }
    return fresultList;
}
bool THSActionUtil::setListenL2GP(int p, string code) {
ConsoleApplication/THSActionUtil.h
@@ -50,6 +50,9 @@
    //识别数字
    static std::list<GPCodeArea>  recognitionNum(cv::Mat img,std::list<GPCodeArea> areaList);
    //识别代码
    static std::list<string> recognitionGPCode(cv::Mat img);
    //设置获取level2的股票数据
    static bool setListenL2GP(int p,string code);
ConsoleApplication/Win32Util.cpp
@@ -26,7 +26,9 @@
    for (int i = 0;i < nums.length();i++)
    {
        keybd_event(nums.c_str()[i], 0, 0, 0);
        Sleep(5);
        keybd_event(nums.c_str()[i], 0, KEYEVENTF_KEYUP, 0);
        Sleep(20);
    }
}
ConsoleApplication/kernel.cl
@@ -61,53 +61,56 @@
    int endx = pos_in[startP + 2];
    int endy = pos_in[startP + 3];
    int startNy = -1;
    int endNy = -1;
    //去除上下的白边
    int y = 0;
    for (y = starty;y <= endy;y++) {
        bool empty = 1;
        for (int x = startx;x <= endx;x++)
        {
            int p = get_one_level_position(width, x, y);
            unsigned char value = get_binary_value(img_in[p]);
            //有数据
            if (value > 0) {
                empty = 0;
    if (startx > 0)
    {
        int startNy = -1;
        int endNy = -1;
        //去除上下的白边
        int y = 0;
        for (y = starty;y <= endy;y++) {
            bool empty = 1;
            for (int x = startx;x <= endx;x++)
            {
                int p = get_one_level_position(width, x, y);
                unsigned char value = get_binary_value(img_in[p]);
                //有数据
                if (value > 0) {
                    empty = 0;
                    break;
                }
            }
            if (!empty) {
                startNy = y;
                break;
            }
        }
        if (!empty) {
            startNy = y;
            break;
        }
    }
    for (y = endy;y >= starty;y--) {
        bool empty = 1;
        for (int x = startx;x <= endx;x++)
        {
            int p = get_one_level_position(width, x, y);
            unsigned char value = get_binary_value(img_in[p]);
            //有数据
            if (value > 0) {
                empty = 0;
        for (y = endy;y >= starty;y--) {
            bool empty = 1;
            for (int x = startx;x <= endx;x++)
            {
                int p = get_one_level_position(width, x, y);
                unsigned char value = get_binary_value(img_in[p]);
                //有数据
                if (value > 0) {
                    empty = 0;
                    break;
                }
            }
            if (!empty) {
                endNy = y;
                break;
            }
        }
        if (!empty) {
            endNy = y;
            break;
        }
        starty = startNy;
        endy = endNy;
    }
    starty = startNy;
    endy = endNy;
    int cols = endx - startx + 1;
    int rows = endy - starty + 1;
    int nps[12];
    if (index % 3 == 0) {
    if (index % 4 == 0) {
        //时间
        int s = cols / 2;
        int i;
        //往前查找冒号
@@ -183,12 +186,68 @@
        nps[11] = endy;
    }
    else if (index % 4 == 1) {
        if (startx > 0 && endx > 0) {
            //分隔s/m/h
            int emptyX = -1;
            for (int x = endx;x >= startx;x--) {
    else if (index % 3 == 1) {
                bool empty = 1;
                for (int y = starty;y <= endy;y++)
                {
                    int p = get_one_level_position(width, x, y);
                    unsigned char value = get_binary_value(img_in[p]);
                    //有数据
                    if (value > 0) {
                        empty = 0;
                        break;
                    }
                }
                if (empty) {
                    emptyX = x;
                    break;
                }
            }
            if (emptyX > 0) {
                nps[0] = startx;
                nps[1] = starty;
                nps[2] = emptyX - 1;
                nps[3] = endy;
            }
            else {
                //printf("撤单时间未解析到分隔符:%d", index);
                nps[0] = -1;
                nps[1] = -1;
                nps[2] = -1;
                nps[3] = -1;
            }
        }
        else {
            nps[0] = -1;
            nps[1] = -1;
            nps[2] = -1;
            nps[3] = -1;
        }
        nps[4] = -1;
        nps[5] = -1;
        nps[6] = -1;
        nps[7] = -1;
        nps[8] = -1;
        nps[9] = -1;
        nps[10] = -1;
        nps[11] = -1;
    }
    else if (index % 4 == 2) {
        //股价
        //printf("startx:%d starty:%d endx:%d endy:%d\n",startx,starty,endx,endy);
        //股价
            //往前查找小数点
        int m_s = -1, m_e = -1;
        uchar temp[6];
@@ -249,7 +308,7 @@
    }
    else if (index % 3 == 2) {
    else if (index % 4 == 3) {
        //手数
        nps[0] = startx;
        nps[1] = starty;
@@ -329,9 +388,12 @@
    }
    int maxNumberCount = 6;
    if (index % 3 == 2)
    if (index % 4 == 3)
    {
        maxNumberCount = 5;
    }
    else if (index % 4 == 1) {
        maxNumberCount = 2;
    }
    int zeroCount = maxNumberCount - numCount;
@@ -383,18 +445,21 @@
        }
        int rowData = num_height * num_width * 10 * num_count;
        int rowIndex = index / 3;
        int rowIndex = index / 4;
        int index_0 = rowData * rowIndex;
        //设置坐标值
        int index_2 = 0;
        if (index % 3 == 0) {
        if (index % 4 == 0) {
            index_2 += num_width * 10 * i;
        }
        else if (index % 3 == 1) {
        else if (index % 4 == 1) {
            index_2 += (num_width * 10) * (6 + i);
        }
        else if (index % 4 == 2) {
            index_2 += (num_width * 10) * (6 + 2 + i);
        }
        else {
            index_2 += (num_width * 10) * (6 + 6 + i);
            index_2 += (num_width * 10) * (6 + 2 + 6 + i);
        }
        for (int re = 0;re < 10;re++) {
@@ -538,14 +603,14 @@
            emptyColIndex2 = 3;
        }
        else if (rowDataSize == 6) {
            //第二个元素开始坐标减去第一个元素结束坐标小于20
            if (rowDataIndexs[4 * 1 + 0] - rowDataIndexs[4 * 0 + 2] < 20) {
                //有买撤,需要补涨停
                emptyColIndex1 = 3;
            //第3个元素的宽度小于第2个元素
            if ((rowDataIndexs[4 * 2 + 2] - rowDataIndexs[4 * 2 + 0]) < (rowDataIndexs[4 * 1 + 2] - rowDataIndexs[4 * 1 + 0])) {
                //有涨停,补买撤
                emptyColIndex1 = 1;
            }
            else {
                //无买撤
                emptyColIndex1 = 1;
                emptyColIndex1 = 3;
            }
        }
        else {
@@ -620,9 +685,61 @@
    __global int* result) {
    int index = get_global_id(0);
    int row = index / 2;
    int row = index / 3;
    int baseIndex = row * 4 * 7;
    if (index % 2 == 0) {
    if (index % 3 == 0) {
        //撤销单位识别
        int startx = baseIndex + 1 * 4;
        int starty = startx + 1;
        int endx = startx + 2;
        int endy = startx + 3;
        if (rowIndexs[startx] > 0) {
            int emptyX = -1;
            for (int x = rowIndexs[endx];x >= rowIndexs[startx];x--)
            {
                bool empty = true;
                for (int y = rowIndexs[starty];y <= rowIndexs[endy];y++) {
                    unsigned char value = imgs[get_one_level_position(width, x, y)];
                    if (get_binary_value(value)) {
                        empty = 0;
                        break;
                    }
                }
                if (empty) {
                    emptyX = x;
                    break;
                }
            }
            if (emptyX > 0) {
                //计算值
                unsigned char count = 0;
                for (int x = emptyX + 1;x <= rowIndexs[endx];x++)
                {
                    for (int y = rowIndexs[starty];y <= rowIndexs[endy];y++) {
                        unsigned char value = imgs[get_one_level_position(width, x, y)];
                        count += get_binary_value(value) ? 1 : 0;
                    }
                }
                //printf("row:%d count:%d\n", row, count);
                if (abs(count - 12) <= 1) {//S
                    result[row * 3] = 0;
                }
                else if (abs(count - 16) <= 1) {//M
                    result[row * 3] = 1;
                }
                else if (abs(count - 19) <= 1) {//H
                    result[row * 3] = 2;
                }
            }
        }
        else {
            //默认s
            result[row * 3] = 0;
            //printf("row:%d count:0\n", row);
        }
    }
    else if (index % 3 == 1) {
        //涨跌停价
        //获取数据坐标
        int startx = baseIndex + 3 * 4;
@@ -630,7 +747,7 @@
        int endx = startx + 2;
        int endy = startx + 3;
        if (rowIndexs[startx] <= 0 && rowIndexs[starty] <= 0 && rowIndexs[endx] <= 0 && rowIndexs[endy] <= 0) {
            result[row * 2] = 0;
            result[row * 3 + 1] = 0;
        }
        else {
            startx = rowIndexs[startx];
@@ -694,11 +811,11 @@
            if (topValue > bottomValue) {
                //涨停
                result[row * 2] = 1;
                result[row * 3 + 1] = 1;
            }
            else {
                //跌停
                result[row * 2] = 2;
                result[row * 3 + 1] = 2;
            }
        }
    }
@@ -721,7 +838,7 @@
        {
            for (int c = startx;c <= endx;c++) {
                unsigned char val = imgs[get_one_level_position(width, c, r)];
                pixelCount+=get_binary_value(val);
                pixelCount += get_binary_value(val);
            }
        }
@@ -743,7 +860,7 @@
            //卖撤
            value = 3;
        }
        result[row * 2 + 1] = value;
        result[row * 3 + 2] = value;
    }
}
app/ExcelUtil.cpp
@@ -44,7 +44,23 @@
        ws->label(index, 0, tradeData.time, xf);
        string t = tradeData.time;
        if (tradeData.cancelTime > 0)
        {
            t.append(" ").append(to_string(tradeData.cancelTime));
            string cancelTimeUnit;
            if (tradeData.cancelTimeUnit == TIME_SECOND) {
                cancelTimeUnit = "s";
            }
            else  if (tradeData.cancelTimeUnit == TIME_MINITE) {
                cancelTimeUnit = "m";
            }
            else  if (tradeData.cancelTimeUnit == TIME_HOUR) {
                cancelTimeUnit = "h";
            }
            t.append(cancelTimeUnit);
        }
        ws->label(index, 0,t, xf);
        ws->label(index, 1, out_str.str(), xf);
        if (tradeData.limitPrice == LIMIT_PRICE_NORMAL) {
            ws->label(index, 2, L"正常价", xf);
app/GUITool.cpp
@@ -27,4 +27,61 @@
        ::CoTaskMemFree(lpidlBrowse);
    }
    return strFolderPath;
}
CString GUITool::selectImage() {
    TCHAR szBuffer[MAX_PATH] = { 0 };
    OPENFILENAME ofn = { 0 };
    ofn.lStructSize = sizeof(ofn);
    ofn.lpstrFilter = _T("All\0*.PNG\0*.JPG");//要选择的文件后缀
    ofn.nFilterIndex = 1;
    ofn.lpstrFile = szBuffer;//存放文件的缓冲区
    ofn.nMaxFile = sizeof(szBuffer) / sizeof(*szBuffer);
    ofn.nFilterIndex = 0;
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
    BOOL bSel = GetOpenFileName(&ofn);
    if (bSel) {
        return szBuffer;
    }
    return 0;
}
std::list<CString> GUITool::selectMulImages() {
    std::list<CString> paths;
    TCHAR szBuffer[MAX_PATH] = { 0 };
    OPENFILENAME ofn = { 0 };
    TCHAR szPath[MAX_PATH];
    int nLen = 0;
    TCHAR* p;
    ofn.lStructSize = sizeof(ofn);
    ofn.lpstrFilter = _T("All\0*.PNG\0*.JPG");//要选择的文件后缀
    ofn.nFilterIndex = 1;
    ofn.lpstrFile = szBuffer;//存放文件的缓冲区
    ofn.nMaxFile = sizeof(szBuffer) / sizeof(*szBuffer);
    ofn.Flags = OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_HIDEREADONLY | OFN_EXPLORER;
    BOOL bSel = GetOpenFileName(&ofn);
    if (bSel) {
        lstrcpyn(szPath, szBuffer, ofn.nFileOffset);
        szPath[ofn.nFileOffset] = '\0';
        nLen = lstrlen(szPath);
        if (szPath[nLen - 1] != '\\') {
            lstrcat(szPath, _T("\\"));
        }
        p = szBuffer + ofn.nFileOffset;
        while (*p) {
            CString name(p);
            CString dir(szPath);
            CString path;
            path.Format(_T("%s%s"), dir, name);
            paths.push_back(path);
            //移至下一个文件
            p += lstrlen(p) + 1;
        }
    }
    return paths;
}
app/GUITool.h
@@ -1,10 +1,15 @@
#pragma once
#include <string>
#include <dwrite.h>
#include <list>
class GUITool
{
public:
    static CString selectFolder(CString title);
    static CString selectImage();
    static std::list<CString> selectMulImages();
};
app/JsonUtil.h
@@ -3,52 +3,77 @@
#include <list>
#include "json/json.h"
#include <THSActionUtil.h>
Json::Value toJson(std::list<TradeData> dataList) {
    Json::Value root;
    std::list<TradeData>::iterator ele;
    int index = 0;
    for (ele = dataList.begin();ele != dataList.end();ele++) {
        Json::Value  item;
        item["time"] = (*ele).time;
        item["price"] = (*ele).price;
        item["num"] = (*ele).num;
        item["limitPrice"] = (*ele).limitPrice;
        item["operateType"] = (*ele).operateType;
        root[index++] = item;
    }
    return root;
}
//json对象转为字符串
std::string toJsonStr(Json::Value json) {
    Json::StreamWriterBuilder writerBuilder;
    //不自动换行
    writerBuilder.settings_["indentation"] = "";
    std::ostringstream os;
    std::unique_ptr<Json::StreamWriter> jsonWriter(writerBuilder.newStreamWriter());
    jsonWriter->write(json, &os);
    string jsonStr = os.str();
    return jsonStr;
}
class JsonUtil {
std::string loadData(int clientID, int channel,string code, std::list<TradeData> dataList) {
    Json::Value data;
    data["channel"] = channel;
    data["code"] = code;
    data["data"] = toJson(dataList);
    Json::Value root;
    root["type"] = 0;
    root["client"] = clientID;
    root["data"] = data;
    return toJsonStr(root);
}
public:
Json::Value parseJson(string data) {
    Json::Value root;
    Json::Reader reader;
    reader.parse(data, root);
    return root;
}
    static  Json::Value toJson(std::list<TradeData> dataList) {
        Json::Value root;
        std::list<TradeData>::iterator ele;
        int index = 0;
        for (ele = dataList.begin();ele != dataList.end();ele++) {
            Json::Value  item;
            item["time"] = (*ele).time;
            item["price"] = (*ele).price;
            item["num"] = (*ele).num;
            item["limitPrice"] = (*ele).limitPrice;
            item["operateType"] = (*ele).operateType;
            item["cancelTime"] = (*ele).cancelTime;
            item["cancelTimeUnit"] = (*ele).cancelTimeUnit;
            root[index++] = item;
        }
        return root;
    }
    //json对象转为字符串
    static  std::string toJsonStr(Json::Value json) {
        Json::StreamWriterBuilder writerBuilder;
        //不自动换行
        writerBuilder.settings_["indentation"] = "";
        std::ostringstream os;
        std::unique_ptr<Json::StreamWriter> jsonWriter(writerBuilder.newStreamWriter());
        jsonWriter->write(json, &os);
        string jsonStr = os.str();
        return jsonStr;
    }
    static  std::string loadL2Data(int clientID, int channel, string code, std::list<TradeData> dataList) {
        Json::Value data;
        data["channel"] = channel;
        data["code"] = code;
        data["data"] = toJson(dataList);
        Json::Value root;
        root["type"] = 0;
        root["client"] = clientID;
        root["data"] = data;
        return toJsonStr(root);
    }
    static  std::string loadGPCodeData(std::list<string> codeList) {
        Json::Value root;
        root["type"] = 1;
        Json::Value data;
        std::list<string>::iterator ele;
        int index = 0;
        for (ele = codeList.begin();ele != codeList.end();ele++) {
            data[index++] = *ele;
        }
        root["data"] = data;
        return toJsonStr(root);
    }
    static  Json::Value parseJson(string data) {
        Json::Value root;
        Json::Reader reader;
        reader.parse(data, root);
        return root;
    }
};
app/SocketManager.cpp
@@ -2,6 +2,7 @@
#include "SocketManager.h"
#define CHANNEL_NUM 9
#include <thread>
#include <string>
SOCKET SocketManager::socketServer;
@@ -47,6 +48,10 @@
                int iSend = send(client, buff, sizeof(buff), 0);
                cout << "设置采集代码出错:" << st << endl;
            }
        }
        else {
            cout << "客户端退出" << endl;
            break;
        }
    }
@@ -167,16 +172,55 @@
    return *ele;
}
void SocketManager::resetClient(int p) {
    WSADATA wsd;
    WSAStartup(MAKEWORD(2, 2), &wsd);
    SOCKET m_SockClient;
    m_SockClient = socket(AF_INET, SOCK_STREAM, 0);
    list<SOCKET>::iterator ele = sockClients.begin();
    advance(ele, p);
    *ele = m_SockClient;
}
BOOL SocketManager::sendMsg(int p, const char* msg) {
    SOCKET socket = getClient(p);
    char buffer[1024];
    send(socket, msg, strlen(msg), 0);
    int num = recv(socket, buffer, 1024, 0);
    if (num >= 0) {
        std::cout << "Receive form server: " << buffer << std::endl;
        return 1;
    char buffer[64];
    int result = send(socket, msg, strlen(msg), 0);
    if (result < 0) {
        throw string("发送失败");
    }
    int num = recv(socket, buffer, 64, 0);
    if (num < 0) {
        throw string("未接收到信息");
    }
    return 0;
    return 1;
}
BOOL SocketManager::sendMsg(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(9001);
    clientaddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    connect(m_SockClient, (sockaddr*)&clientaddr, sizeof(clientaddr));
    char buffer[64];
    int result = send(m_SockClient, msg, strlen(msg), 0);
    if (result < 0) {
        throw string("发送失败");
    }
    int num = recv(m_SockClient, buffer, 64, 0);
    closesocket(m_SockClient);
    if (num < 0) {
        throw string("未接收到信息");
    }
    return 1;
}
app/SocketManager.h
@@ -26,7 +26,7 @@
    static void runSocketServer(void* context);
    static void processMsg(SOCKET  client, void* context);
    const int PORT = 9001;
    const char* ADDR = "127.0.0.1";
    const char *ADDR = "127.0.0.1";
    sockaddr_in clientaddr;
    SOCKET getClient(int p);
    //添加客户端
@@ -43,6 +43,8 @@
    int getClientsNum();
    void resetClient(int p);
    //连接所有
    int Connect();
    int Connect(int p);
@@ -53,6 +55,8 @@
    BOOL sendMsg(int, const char *);
    static BOOL sendMsg(const char*);
};
app/app.aps
Binary files differ
app/app.rc
Binary files differ
app/app.vcxproj
@@ -194,6 +194,7 @@
  <ItemGroup>
    <ClInclude Include="app.h" />
    <ClInclude Include="BasicExcelVC6.hpp" />
    <ClInclude Include="codesDataDlog.h" />
    <ClInclude Include="ExcelUtil.h" />
    <ClInclude Include="GUITool.h" />
    <ClInclude Include="JsonUtil.h" />
@@ -215,10 +216,12 @@
    <ClInclude Include="Resource.h" />
    <ClInclude Include="SocketManager.h" />
    <ClInclude Include="targetver.h" />
    <ClInclude Include="tool.h" />
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="app.cpp" />
    <ClCompile Include="BasicExcelVC6.cpp" />
    <ClCompile Include="codesDataDlog.cpp" />
    <ClCompile Include="ExcelUtil.cpp" />
    <ClCompile Include="GUITool.cpp" />
    <ClCompile Include="json_reader.cpp" />
app/app.vcxproj.filters
@@ -90,6 +90,12 @@
    <ClInclude Include="JsonUtil.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="tool.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="codesDataDlog.h">
      <Filter>头文件</Filter>
    </ClInclude>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="app.cpp">
@@ -128,6 +134,9 @@
    <ClCompile Include="NetWorkUtil.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="codesDataDlog.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="app.rc">
app/appDlg.cpp
@@ -8,8 +8,11 @@
#include "appDlg.h"
#include "afxdialogex.h"
#include "level2DataDlg.h"
#include "codesDataDlog.h"
#include "THSActionUtil.h"
#include "NetWorkUtil.h"
#include "GUITool.h"
#include "tool.h"
#include "JsonUtil.h"
#ifdef _DEBUG
@@ -84,6 +87,8 @@
    ON_BN_CLICKED(IDC_BUTTON4, &CappDlg::OnBnClickedButton4)
    ON_BN_CLICKED(IDC_BUTTON20, &CappDlg::OnBnClickedButton20)
    ON_BN_CLICKED(IDC_BUTTON5, &CappDlg::OnBnClickedButton5)
    ON_BN_CLICKED(IDC_BUTTON7, &CappDlg::OnBnClickedButton7)
    ON_BN_CLICKED(IDC_BUTTON8, &CappDlg::OnBnClickedButton8)
END_MESSAGE_MAP()
@@ -127,6 +132,15 @@
    st.Format(_T("本机IP:%s"), ipStr);
    GetDlgItem(IDC_STATIC3)->SetWindowTextW(st);
    if (!capture->isInited())
    {
        try {
            capture->init(OnDataCallback, this);
        }
        catch (string st) {
        }
    }
    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}
@@ -193,8 +207,17 @@
    CButton* btn = (CButton*)app->GetDlgItem(IDC_CHECK1);
    bool check = btn->GetCheck();
    if (check) {
        string data = loadData(0, index, code, dataList);
        app->socketManager->sendMsg(index, data.c_str());
        string data = JsonUtil::loadL2Data(0, index, code, dataList);
        clock_t time_start = clock();
        try {
            app->socketManager->sendMsg(index, data.c_str());
        }
        catch (string st) {
            //重新连接服务器
            app->socketManager->resetClient(index);
            app->socketManager->Connect(index);
        }
        cout<<"*****数据处理时间:"<<(clock()- time_start)<<endl;
    }
}
@@ -204,7 +227,7 @@
    CappDlg* app = (CappDlg*)context;
    cout << "action回调:" << std::this_thread::get_id() << ":" << data << endl;
    //解析命令
    Json::Value root = parseJson(data);
    Json::Value root = JsonUtil::parseJson(data);
    if (root["action"].asString() == "setGPCode") {
        //设置股票代码
        int index = root["data"]["index"].asInt();
@@ -212,7 +235,10 @@
        string quickCode = "5";
        quickCode.append(to_string(index + 1));
        list<string> codeList;
        codeList.push_back(code);
        if (code.length() > 0)
        {
            codeList.push_back(code);
        }
        try {
            if (!app->capture->isInited()) {
@@ -237,9 +263,11 @@
            }
        }
        catch (string e) {
            CString msg(e.c_str());
            AfxMessageBox(msg);
            //CString msg(e.c_str());
            //AfxMessageBox(msg);
            throw e;
        }catch (...) {
            throw string("未知错误");
        }
        //恢复采集
@@ -339,7 +367,13 @@
        }
    }
    clock_t time = clock();
    list<TradeData> result = capture->captureLevel2TradeData(cv::imread("C:\\Users\\Administrator\\Desktop\\ocr\\new.jpg"), 0);
    CString path= GUITool::selectImage();
   std:string p = cstring2String(path);
    if (p.length() <= 0) {
        return;
    }
    list<TradeData> result = capture->captureLevel2TradeData(cv::imread(p), 0);
    time = clock() - time;
    Clevel2DataDlg::level2Data = { time, result };
@@ -351,28 +385,29 @@
//截图识别
void CappDlg::OnBnClickedButton4()
{
    POINT pNow = { 0,0 };
    if (GetCursorPos(&pNow))  // 获取鼠标当前位置
    if (!capture->isInited())
    {
        HWND hwndPointNow = NULL;
        hwndPointNow = (HWND)WindowFromPoint(pNow);  // 获取鼠标所在窗口的句柄
        if (hwndPointNow)
        {
            char szWindowTitle[50];
            ::GetWindowTextA(hwndPointNow, szWindowTitle, sizeof(szWindowTitle));  // 获取窗口标题
            cout << hex << (int)hwndPointNow << endl;  // 鼠标所在窗口的句柄
            cout << szWindowTitle << endl;  // 鼠标所在窗口的标题
        try {
            capture->init(OnDataCallback, this);
        }
        else
            cout << "Error!!" << endl;
        catch (string st) {
            CString msg(st.c_str());
            AfxMessageBox(msg);
        }
    }
    clock_t time = clock();
    CString path = GUITool::selectImage();
    std:string p = cstring2String(path);
    if (p.length() <= 0) {
        return;
    }
    list<TradeData> result = capture->captureLevel2TradeData(cv::imread(p), 0);
    time = clock() - time;
    Clevel2DataDlg::level2Data = { time, result };
    Clevel2DataDlg dlg;
    dlg.DoModal();
}
//环境检测
@@ -449,3 +484,84 @@
}
//股票代码识别
void CappDlg::OnBnClickedButton7()
{
    if (!capture->isInited())
    {
        try {
            capture->init(OnDataCallback, this);
        }
        catch (string st) {
            CString msg(st.c_str());
            AfxMessageBox(msg);
            return;
        }
    }
    list<CString> paths= GUITool::selectMulImages();
    std::list<string> fResultList;
    for (list<CString>::iterator ele = paths.begin();ele != paths.end();ele++) {
        CString path = *ele;
        std:string p = cstring2String(path);
        std::list<string> resultList =    THSActionUtil::recognitionGPCode(cv::imread(p));
        for (std::list<string>::iterator ele1 = resultList.begin();ele1 != resultList.end();ele1++) {
            bool contains = false;
            for (std::list<string>::iterator e = fResultList.begin();e != fResultList.end();e++) {
                if (*e == *ele1) {
                    contains = true;
                    break;
                }
            }
            if (!contains) {
                fResultList.push_back(*ele1);
            }
        }
    }
    codesDataDlog::codeData = fResultList;
    codesDataDlog::upload = false;
    codesDataDlog dlg;
    dlg.DoModal();
}
//截图上传股票代码
void CappDlg::OnBnClickedButton8()
{
    //
    if (!capture->isInited())
    {
        try {
            capture->init(OnDataCallback, this);
        }
        catch (string st) {
            CString msg(st.c_str());
            AfxMessageBox(msg);
            return;
        }
    }
    list<CString> paths = GUITool::selectMulImages();
    std::list<string> fResultList;
    for (list<CString>::iterator ele = paths.begin();ele != paths.end();ele++) {
        CString path = *ele;
    std:string p = cstring2String(path);
        std::list<string> resultList = THSActionUtil::recognitionGPCode(cv::imread(p));
        for (std::list<string>::iterator ele1 = resultList.begin();ele1 != resultList.end();ele1++) {
            bool contains = false;
            for (std::list<string>::iterator e = fResultList.begin();e != fResultList.end();e++) {
                if (*e == *ele1) {
                    contains = true;
                    break;
                }
            }
            if (!contains) {
                fResultList.push_back(*ele1);
            }
        }
    }
    codesDataDlog::codeData = fResultList;
    codesDataDlog::upload = TRUE;
    codesDataDlog dlg;
    dlg.DoModal();
}
app/appDlg.h
@@ -59,4 +59,6 @@
    afx_msg void OnBnClickedButton4();
    afx_msg void OnBnClickedButton20();
    afx_msg void OnBnClickedButton5();
    afx_msg void OnBnClickedButton7();
    afx_msg void OnBnClickedButton8();
};
app/codesDataDlog.cpp
New file
@@ -0,0 +1,121 @@
// codesDataDlog.cpp: 实现文件
//
#include "pch.h"
#include "codesDataDlog.h"
#include "afxdialogex.h"
#include "framework.h"
#include "GUITool.h"
#include "ExcelUtil.h"
#include "app.h"
#include "SocketManager.h"
#include "JsonUtil.h"
// codesDataDlog 对话框
IMPLEMENT_DYNAMIC(codesDataDlog, CDialogEx)
std::list<string> codesDataDlog::codeData;
bool  codesDataDlog::upload;
codesDataDlog::codesDataDlog(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_CODE_DATA, pParent)
{
}
codesDataDlog::~codesDataDlog()
{
}
void codesDataDlog::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_BUTTON1, uploadBtn);
}
BOOL codesDataDlog::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // 将“关于...”菜单项添加到系统菜单中。
    // IDM_ABOUTBOX 必须在系统命令范围内。
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);
    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != nullptr)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }
    if (upload)
        uploadBtn.ShowWindow(TRUE);
    else
        uploadBtn.ShowWindow(FALSE);
    CString st;
    st.Format(_T("总共%d条数据"), codeData.size());
    GetDlgItem(IDC_STATIC)->SetWindowTextW(st);
    CEdit* edit = (CEdit*)GetDlgItem(IDC_EDIT2);
    string data = "";
    for (list<string>::iterator ele = codeData.begin();ele != codeData.end();ele++) {
        data.append(*ele).append("\r\n");
    }
    CString cdata(data.c_str());
    edit->SetWindowTextW(cdata);
    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}
BEGIN_MESSAGE_MAP(codesDataDlog, CDialogEx)
    ON_BN_CLICKED(IDC_BUTTON1, &codesDataDlog::OnBnClickedButton1)
END_MESSAGE_MAP()
// codesDataDlog 消息处理程序
void codesDataDlog::OnBnClickedButton1()
{
    if (codeData.size() == 0) {
        AfxMessageBox(_T("没有可上传的代码"));
        return;
    }
    bool
        result = SocketManager::sendMsg(JsonUtil::loadGPCodeData(codeData).c_str());
    if (result) {
        AfxMessageBox(_T("上传成功"));
    }
    else {
        AfxMessageBox(_T("上传失败"));
    }
}
app/codesDataDlog.h
New file
@@ -0,0 +1,33 @@
#pragma once
#include "ScreenDataCapture.h"
// codesDataDlog 对话框
class codesDataDlog : public CDialogEx
{
    DECLARE_DYNAMIC(codesDataDlog)
public:
    static std::list<string> codeData;
    static bool upload;
public:
    codesDataDlog(CWnd* pParent = nullptr);   // 标准构造函数
    virtual ~codesDataDlog();
// 对话框数据
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_CODE_DATA };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    virtual BOOL OnInitDialog();
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnBnClickedButton1();
    CButton uploadBtn;
};
app/kernel.cl
@@ -61,53 +61,56 @@
    int endx = pos_in[startP + 2];
    int endy = pos_in[startP + 3];
    int startNy = -1;
    int endNy = -1;
    //去除上下的白边
    int y = 0;
    for (y = starty;y <= endy;y++) {
        bool empty = 1;
        for (int x = startx;x <= endx;x++)
        {
            int p = get_one_level_position(width, x, y);
            unsigned char value = get_binary_value(img_in[p]);
            //有数据
            if (value > 0) {
                empty = 0;
    if (startx > 0)
    {
        int startNy = -1;
        int endNy = -1;
        //去除上下的白边
        int y = 0;
        for (y = starty;y <= endy;y++) {
            bool empty = 1;
            for (int x = startx;x <= endx;x++)
            {
                int p = get_one_level_position(width, x, y);
                unsigned char value = get_binary_value(img_in[p]);
                //有数据
                if (value > 0) {
                    empty = 0;
                    break;
                }
            }
            if (!empty) {
                startNy = y;
                break;
            }
        }
        if (!empty) {
            startNy = y;
            break;
        }
    }
    for (y = endy;y >= starty;y--) {
        bool empty = 1;
        for (int x = startx;x <= endx;x++)
        {
            int p = get_one_level_position(width, x, y);
            unsigned char value = get_binary_value(img_in[p]);
            //有数据
            if (value > 0) {
                empty = 0;
        for (y = endy;y >= starty;y--) {
            bool empty = 1;
            for (int x = startx;x <= endx;x++)
            {
                int p = get_one_level_position(width, x, y);
                unsigned char value = get_binary_value(img_in[p]);
                //有数据
                if (value > 0) {
                    empty = 0;
                    break;
                }
            }
            if (!empty) {
                endNy = y;
                break;
            }
        }
        if (!empty) {
            endNy = y;
            break;
        }
        starty = startNy;
        endy = endNy;
    }
    starty = startNy;
    endy = endNy;
    int cols = endx - startx + 1;
    int rows = endy - starty + 1;
    int nps[12];
    if (index % 3 == 0) {
    if (index % 4 == 0) {
        //时间
        int s = cols / 2;
        int i;
        //往前查找冒号
@@ -183,12 +186,68 @@
        nps[11] = endy;
    }
    else if (index % 4 == 1) {
        if (startx > 0 && endx > 0) {
            //分隔s/m/h
            int emptyX = -1;
            for (int x = endx;x >= startx;x--) {
    else if (index % 3 == 1) {
                bool empty = 1;
                for (int y = starty;y <= endy;y++)
                {
                    int p = get_one_level_position(width, x, y);
                    unsigned char value = get_binary_value(img_in[p]);
                    //有数据
                    if (value > 0) {
                        empty = 0;
                        break;
                    }
                }
                if (empty) {
                    emptyX = x;
                    break;
                }
            }
            if (emptyX > 0) {
                nps[0] = startx;
                nps[1] = starty;
                nps[2] = emptyX - 1;
                nps[3] = endy;
            }
            else {
                //printf("撤单时间未解析到分隔符:%d", index);
                nps[0] = -1;
                nps[1] = -1;
                nps[2] = -1;
                nps[3] = -1;
            }
        }
        else {
            nps[0] = -1;
            nps[1] = -1;
            nps[2] = -1;
            nps[3] = -1;
        }
        nps[4] = -1;
        nps[5] = -1;
        nps[6] = -1;
        nps[7] = -1;
        nps[8] = -1;
        nps[9] = -1;
        nps[10] = -1;
        nps[11] = -1;
    }
    else if (index % 4 == 2) {
        //股价
        //printf("startx:%d starty:%d endx:%d endy:%d\n",startx,starty,endx,endy);
        //股价
            //往前查找小数点
        int m_s = -1, m_e = -1;
        uchar temp[6];
@@ -249,7 +308,7 @@
    }
    else if (index % 3 == 2) {
    else if (index % 4 == 3) {
        //手数
        nps[0] = startx;
        nps[1] = starty;
@@ -329,9 +388,12 @@
    }
    int maxNumberCount = 6;
    if (index % 3 == 2)
    if (index % 4 == 3)
    {
        maxNumberCount = 5;
    }
    else if (index % 4 == 1) {
        maxNumberCount = 2;
    }
    int zeroCount = maxNumberCount - numCount;
@@ -383,18 +445,21 @@
        }
        int rowData = num_height * num_width * 10 * num_count;
        int rowIndex = index / 3;
        int rowIndex = index / 4;
        int index_0 = rowData * rowIndex;
        //设置坐标值
        int index_2 = 0;
        if (index % 3 == 0) {
        if (index % 4 == 0) {
            index_2 += num_width * 10 * i;
        }
        else if (index % 3 == 1) {
        else if (index % 4 == 1) {
            index_2 += (num_width * 10) * (6 + i);
        }
        else if (index % 4 == 2) {
            index_2 += (num_width * 10) * (6 + 2 + i);
        }
        else {
            index_2 += (num_width * 10) * (6 + 6 + i);
            index_2 += (num_width * 10) * (6 + 2 + 6 + i);
        }
        for (int re = 0;re < 10;re++) {
@@ -538,14 +603,14 @@
            emptyColIndex2 = 3;
        }
        else if (rowDataSize == 6) {
            //第二个元素开始坐标减去第一个元素结束坐标小于20
            if (rowDataIndexs[4 * 1 + 0] - rowDataIndexs[4 * 0 + 2] < 20) {
                //有买撤,需要补涨停
                emptyColIndex1 = 3;
            //第3个元素的宽度小于第2个元素
            if ((rowDataIndexs[4 * 2 + 2] - rowDataIndexs[4 * 2 + 0]) < (rowDataIndexs[4 * 1 + 2] - rowDataIndexs[4 * 1 + 0])) {
                //有涨停,补买撤
                emptyColIndex1 = 1;
            }
            else {
                //无买撤
                emptyColIndex1 = 1;
                emptyColIndex1 = 3;
            }
        }
        else {
@@ -620,9 +685,51 @@
    __global int* result) {
    int index = get_global_id(0);
    int row = index / 2;
    int row = index / 3;
    int baseIndex = row * 4 * 7;
    if (index % 2 == 0) {
    if (index % 3 == 0) {
        //撤销单位识别
        int startx = baseIndex + 1 * 4;
        int starty = startx + 1;
        int endx = startx + 2;
        int endy = startx + 3;
        if (rowIndexs[startx] > 0) {
            int emptyX = -1;
            for (int x = endx;x >= startx;x--)
            {
                bool empty = true;
                for (int y = starty;y <= endy;y++) {
                    unsigned char value = imgs[get_one_level_position(width, x, y)];
                    if (get_binary_value(value)) {
                        empty = 0;
                        break;
                    }
                }
                if (empty) {
                    emptyX = x;
                    break;
                }
            }
            if (emptyX > 0) {
                startx = emptyX + 1;
            }
            //计算值
            unsigned char count = 0;
            for (int x = startx;x <= endx;x++)
            {
                for (int y = starty;y <= endy;y++) {
                    unsigned char value = imgs[get_one_level_position(width, x, y)];
                    count += get_binary_value(value) ? 1 : 0;
                }
            }
            printf("count:%d",count);
            result[row * 3] = 0;
        }
        else {
            result[row * 3] = 0;
        }
    }
    else if (index % 3 == 1) {
        //涨跌停价
        //获取数据坐标
        int startx = baseIndex + 3 * 4;
@@ -630,7 +737,7 @@
        int endx = startx + 2;
        int endy = startx + 3;
        if (rowIndexs[startx] <= 0 && rowIndexs[starty] <= 0 && rowIndexs[endx] <= 0 && rowIndexs[endy] <= 0) {
            result[row * 2] = 0;
            result[row * 3+1] = 0;
        }
        else {
            startx = rowIndexs[startx];
@@ -694,11 +801,11 @@
            if (topValue > bottomValue) {
                //涨停
                result[row * 2] = 1;
                result[row * 3+1] = 1;
            }
            else {
                //跌停
                result[row * 2] = 2;
                result[row * 3+1] = 2;
            }
        }
    }
@@ -721,7 +828,7 @@
        {
            for (int c = startx;c <= endx;c++) {
                unsigned char val = imgs[get_one_level_position(width, c, r)];
                pixelCount+=get_binary_value(val);
                pixelCount += get_binary_value(val);
            }
        }
@@ -743,7 +850,7 @@
            //卖撤
            value = 3;
        }
        result[row * 2 + 1] = value;
        result[row * 3 + 2] = value;
    }
}
app/level2DataDlg.cpp
@@ -29,6 +29,7 @@
void Clevel2DataDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_LIST1, m_list);
}
BEGIN_MESSAGE_MAP(Clevel2DataDlg, CDialogEx)
@@ -77,9 +78,14 @@
    GetDlgItem(IDC_STATIC)->SetWindowTextW(st);
    //设置list的数据
    list<TradeData>::iterator ele;
    CListBox* listBox = (CListBox*)GetDlgItem(IDC_LIST1);
    CString st1;
    st1.Format(_T("%-3s %10s    %6s %5s %s %8s"), _T("序号"), _T("时间"), _T("价格"), _T("是否涨停价"), _T("手数"), _T("类型"));
    m_list.InsertColumn(0, _T("序号"), LVCFMT_CENTER, 40);
    m_list.InsertColumn(1, _T("时间"), LVCFMT_LEFT, 80);
    m_list.InsertColumn(2, _T("价格"), LVCFMT_CENTER, 80);
    m_list.InsertColumn(3, _T("手数"), LVCFMT_CENTER, 50);
    m_list.InsertColumn(4, _T("类型"), LVCFMT_RIGHT, 40);
    int index = 0;
@@ -103,13 +109,44 @@
            break;
        }
        CString st;
        st.Format(_T("%03d %15s    %6.2f %10s %05d %10s"), index, time, stof(data.price), data.limitPrice ? _T("涨停价") : _T("非涨停"), data.num, operate);
        char chCode[20];
        sprintf(chCode, "%.2lf", stod(data.price));
        std::string price(chCode);
        listBox->InsertString(index - 1, st);
        if (data.limitPrice == LIMIT_PRICE_NORMAL) {
            price.append("(正常)");
        }
        else  if (data.limitPrice == LIMIT_PRICE_UP) {
            price.append("(涨停)");
        }
        else  if (data.limitPrice == LIMIT_PRICE_DOWN) {
            price.append("(跌停)");
        }
        string t=data.time;
        if (data.cancelTime > 0)
        {
            t.append(" ").append(to_string( data.cancelTime));
            string cancelTimeUnit;
            if (data.cancelTimeUnit == TIME_SECOND) {
                cancelTimeUnit = "s";
            }
            else  if (data.cancelTimeUnit == TIME_MINITE) {
                cancelTimeUnit = "m";
            }
            else  if (data.cancelTimeUnit == TIME_HOUR) {
                cancelTimeUnit = "h";
            }
            t.append(cancelTimeUnit);
        }
        m_list.InsertItem(index-1, NULL);
        m_list.SetItemText(index - 1, 0, CString(to_string( index).c_str()));
        m_list.SetItemText(index - 1, 1, CString(t.c_str()));
        m_list.SetItemText(index - 1, 2, CString(price.c_str()));
        m_list.SetItemText(index - 1, 3, CString(to_string(data.num).c_str()));
        m_list.SetItemText(index - 1, 4, operate);
    }
    listBox->InsertString(0, st1);
@@ -157,10 +194,13 @@
void Clevel2DataDlg::OnBnClickedButton1()
{
    CString root=    GUITool::selectFolder(_T("请选择导出的目录"));
    CString root = GUITool::selectFolder(_T("请选择导出的目录"));
    string path = (CW2A(root.GetString()));
    path.append("\\").append(to_string( time(0))).append( ".xls");
    ExcelUtil::save(level2Data.dataList,path);
    if (path.length() > 0)
    {
        path.append("\\").append(to_string(time(0))).append(".xls");
        ExcelUtil::save(level2Data.dataList, path);
    AfxMessageBox(_T("保存成功"));
        AfxMessageBox(_T("保存成功"));
    }
}
app/level2DataDlg.h
@@ -45,4 +45,6 @@
public:
    afx_msg void OnLbnSelchangeList1();
    afx_msg void OnBnClickedButton1();
private:
    CListCtrl m_list;
};
app/resource.h
@@ -9,6 +9,7 @@
#define IDD_APP_DIALOG                  102
#define IDR_MAINFRAME                   128
#define IDD_LEVEL2_DATA                 130
#define IDD_CODE_DATA                   132
#define IDC_BUTTON4                     1004
#define IDC_BUTTON5                     1005
#define IDC_BUTTON6                     1006
@@ -21,14 +22,15 @@
#define IDC_BUTTON1                     1013
#define IDC_BUTTON20                    1014
#define IDC_STATIC3                     1016
#define IDC_EDIT2                       1018
// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        132
#define _APS_NEXT_RESOURCE_VALUE        134
#define _APS_NEXT_COMMAND_VALUE         32771
#define _APS_NEXT_CONTROL_VALUE         1017
#define _APS_NEXT_CONTROL_VALUE         1020
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif
app/tool.h
New file
@@ -0,0 +1,11 @@
#pragma once
#include <tchar.h>
#include <string>
#include <stringapiset.h>
std::string cstring2String(CString getbuf) {
    int iLen = WideCharToMultiByte(CP_ACP, 0, getbuf, -1, NULL, 0, NULL, NULL);   //首先计算TCHAR 长度。
    char* chRtn = new char[iLen * sizeof(char)];  //定义一个 TCHAR 长度大小的 CHAR 类型。
    WideCharToMultiByte(CP_ACP, 0, getbuf, -1, chRtn, iLen, NULL, NULL);  //将TCHAR 类型的数据转换为 CHAR 类型。
    std::string str(chRtn);
    return str;
}