commit 50e9883a7914d4a308f3b2da2bf3ce3494b23388 Author: xiewenji <527774126@qq.com> Date: Mon Jun 15 17:05:46 2026 +0800 Initial commit from BOE_CELL_AOI_Detect diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..286242b --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/build +/lib +/include +/data +/SaveImg +.vscode/launch.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..2c74a72 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,17 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**", + "/usr/local/include/opencv4" + ], + "defines": [], + "compilerPath": "/usr/bin/gcc", + "cStandard": "c17", + "cppStandard": "gnu++14", + "intelliSenseMode": "linux-gcc-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6c4f661 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,84 @@ +{ + "files.associations": { + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "array": "cpp", + "atomic": "cpp", + "bitset": "cpp", + "chrono": "cpp", + "codecvt": "cpp", + "complex": "cpp", + "condition_variable": "cpp", + "cstdint": "cpp", + "deque": "cpp", + "list": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "filesystem": "cpp", + "functional": "cpp", + "iterator": "cpp", + "map": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "set": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "future": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "cinttypes": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "variant": "cpp", + "bit": "cpp", + "regex": "cpp", + "shared_mutex": "cpp", + "__nullptr": "cpp", + "__split_buffer": "cpp", + "__locale": "cpp", + "__atomic": "cpp", + "__bit_reference": "cpp", + "__functional_base": "cpp", + "__node_handle": "cpp", + "__memory": "cpp", + "locale": "cpp", + "ios": "cpp", + "__hash_table": "cpp", + "__tree": "cpp", + "queue": "cpp", + "stack": "cpp", + "__mutex_base": "cpp" + }, + "C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json" +} \ No newline at end of file diff --git a/AIEngineModule/example/CMakeLists.txt b/AIEngineModule/example/CMakeLists.txt new file mode 100644 index 0000000..d38adf6 --- /dev/null +++ b/AIEngineModule/example/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required (VERSION 3.5) +find_package( OpenCV REQUIRED ) + +message(STATUS "oPENCV Library status:") +message(STATUS ">version:${OpenCV_VERSION}") +message(STATUS "Include:${OpenCV_INCLUDE_DIRS}") + + +set(CMAKE_CXX_STANDARD 17) + +set(CMAKE_CXX_FLAGS "-Wno-error=deprecated-declarations -Wno-deprecated-declarations") + +find_package(CUDA REQUIRED) +message(STATUS "cuda version: " ${CUDA_VERSION_STRING}) +message(STATUS "cuda CUDA_INCLUDE_DIRS: " ${CUDA_INCLUDE_DIRS}) +include_directories(${CUDA_INCLUDE_DIRS}) + +include_directories( +${CMAKE_CURRENT_SOURCE_DIR}/include +${PROJECT_SOURCE_DIR}/AIEngineModule/include +${PROJECT_SOURCE_DIR}/AIEngineModule/include_base +) + +link_directories( +/usr/local/lib/ +) +set(CMAKE_CUDA_ARCHITECTURES 86) +set(CMAKE_CUDA_COMPILER "/usr/local/cuda/bin/nvcc") +enable_language(CUDA) +file(GLOB SRC_LISTS + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp + ${PROJECT_SOURCE_DIR}/AIEngineModule/src/*.cpp + ${PROJECT_SOURCE_DIR}/AIEngineModule/src/*.c + ${PROJECT_SOURCE_DIR}/AIEngineModule/src/*.cu +) + +add_executable("ai_test" ${SRC_LISTS}) + +target_link_libraries("ai_test" + pthread + z + nvinfer + ${CUDA_LIBRARIES} + ${OpenCV_LIBS} +) diff --git a/AIEngineModule/example/deal.cpp b/AIEngineModule/example/deal.cpp new file mode 100644 index 0000000..912bce6 --- /dev/null +++ b/AIEngineModule/example/deal.cpp @@ -0,0 +1,9 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-07-04 16:18:48 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-07-04 16:23:28 + * @FilePath: /AI_SO_Test/AIEngineModule/example/deal.cpp + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#include "deal.h" \ No newline at end of file diff --git a/AIEngineModule/example/deal.h b/AIEngineModule/example/deal.h new file mode 100644 index 0000000..b8216e0 --- /dev/null +++ b/AIEngineModule/example/deal.h @@ -0,0 +1,5 @@ + +#ifndef _deal_HPP_ +#define _deal_HPP_ + +#endif //_CORELOGICFACTORY_HPP_ \ No newline at end of file diff --git a/AIEngineModule/example/test_example.cpp b/AIEngineModule/example/test_example.cpp new file mode 100644 index 0000000..0346522 --- /dev/null +++ b/AIEngineModule/example/test_example.cpp @@ -0,0 +1,304 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-07-04 16:18:48 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-06 22:37:59 + * @FilePath: /AI_SO_Test/AIEngineModule/example/test_example.cpp + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#include +#include +#include +#include "deal.h" +#include +#include +#include +#include +#include +#include "AI_Factory.h" +#include +#include +#include +#include +#include +#include +#include +#include +long getcurTime() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return ((long)tv.tv_sec) * 1000 + ((long)tv.tv_usec) / 1000; +} +void handler(int sig) +{ + printf("Get handler sig"); + std::string strcmd = "ps -ef | grep test_JBL_Check| awk '{print $2}' | xargs kill -9 "; + const char *cmd = strcmd.c_str(); + printf("delete test_JBL_Check success"); + if (-1 == system(cmd)) + { + std::cout << "error" << std::endl; + } + + // delete UnderCarriageCoreLogic::GetInstance(); + exit(0); +} + +int _sysmkdir(const std::string &dir) +{ + int ret = mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if (ret && errno == EEXIST) + { + // printf("dir[%s] already exist.\n", dir.c_str()); + } + else if (ret) + { + printf("create dir[%s] error: %d %s\n", dir.c_str(), ret, strerror(errno)); + return -1; + } + else + { + printf("create dir[%s] success.\n", dir.c_str()); + } + return 0; +} +std::string __getParentDir(const std::string &dir) +{ + std::string pdir = dir; + if (pdir.length() < 1 || (pdir[0] != '/')) + { + return ""; + } + while (pdir.length() > 1 && (pdir[pdir.length() - 1] == '/')) + pdir = pdir.substr(0, pdir.length() - 1); + + pdir = pdir.substr(0, pdir.find_last_of('/')); + return pdir; +} +int _sysmkdirs(const std::string &dir) +{ + int ret = 0; + if (dir.empty()) + return -1; + std::string pdir; + if ((ret = _sysmkdir(dir)) == -1) + { + pdir = __getParentDir(dir); + if ((ret = _sysmkdirs(pdir)) == 0) + { + ret = _sysmkdirs(dir); + } + } + + return ret; +} + +int main(int argc, char *argv[]) +{ + + std::shared_ptr AI_Factory; + AI_Factory = AIFactory::GetInstance(); + + GPU_Config gpu; + gpu.gpu_0 = true; + gpu.gpu_1 = true; + + AI_Factory->InitALLAIModle(gpu); + std::shared_ptr BOE_Edge_Detect = AI_Factory->BOE_Edge_Detect; + BOE_Edge_Detect->input_0.print(); + BOE_Edge_Detect->input_1.print(); + BOE_Edge_Detect->output_0.print(); + BOE_Edge_Detect->output_1.print(); + BOE_Edge_Detect->output_2.print(); + std::shared_ptr JBL_Detect = AI_Factory->JBL_Detect; + JBL_Detect->input_0.print(); + JBL_Detect->input_1.print(); + JBL_Detect->output_0.print(); + JBL_Detect->output_1.print(); + JBL_Detect->output_2.print(); + + cv::Mat temimg = cv::imread("../data/20250319_192154_Main_0_2_L255_Org.tif", 0); + cv::Mat dealImg; + printf("src img %d %d \n", temimg.cols, temimg.rows); + + cv::Size sz = cv::Size(BOE_Edge_Detect->input_0.width, BOE_Edge_Detect->input_0.height); + + cv::resize(temimg, dealImg, cv::Size(BOE_Edge_Detect->input_0.width, BOE_Edge_Detect->input_0.height)); + cv::Mat outimg; + + BOE_Edge_Detect->AIDet(dealImg, outimg); + cv::imwrite("outimg.png", outimg); + + { + long t1 = getcurTime(); + cv::Mat output; + for (int i = 0; i < 1000; ++i) + { + cv::resize(temimg, dealImg, sz); + BOE_Edge_Detect->AIDet(dealImg, outimg); + } + + long t2 = getcurTime(); + + // std::cout << "== run 1000 : " << t2 - t1 << " 毫秒" << std::endl; + // cv::imwrite(name + "_output.jpg", output); + // std::cout << "[" << name << "] done\n"; + }; + printf("========================\n"); + { + long t1 = getcurTime(); + + // Lambda 线程函数 + auto run_detection = [](std::shared_ptr engine, const cv::Mat &input, const cv::Size sz, const std::string &name) + { + cv::Mat output; + for (int i = 0; i < 250; ++i) + { + cv::Mat dealImg123; + cv::resize(input, dealImg123, sz); + // printf("%s ---- \n",name.c_str()); + engine->AIDet(dealImg123, output); + // cv::imwrite(name + "_" + std::to_string(i) + "_output.jpg", output); + } + // cv::imwrite(name + "_output.jpg", output); + // std::cout << "[" << name << "] done\n"; + }; + + // 启动两个线程 + std::thread thread1(run_detection, BOE_Edge_Detect, temimg, sz, "manager1"); + std::thread thread2(run_detection, BOE_Edge_Detect, temimg, sz, "manager2"); + std::thread thread3(run_detection, BOE_Edge_Detect, temimg, sz, "manager3"); + std::thread thread4(run_detection, BOE_Edge_Detect, temimg, sz, "manager4"); + // std::thread thread5(run_detection, BOE_Edge_Detect, dealImg, "manager1"); + // std::thread thread6(run_detection, BOE_Edge_Detect, dealImg, "manager2"); + // std::thread thread7(run_detection, BOE_Edge_Detect, dealImg, "manager3"); + // std::thread thread8(run_detection, BOE_Edge_Detect, dealImg, "manager4"); + // 等待线程结束 + thread1.join(); + thread2.join(); + thread3.join(); + thread4.join(); + // thread5.join(); + // thread6.join(); + // thread7.join(); + // thread8.join(); + + long t2 = getcurTime(); + // std::cout << "run 1000 = thread 4 * 250 耗时: " << t2 - t1 << " 毫秒" << std::endl; + } + + cv::Mat dealImg123; + cv::resize(temimg, dealImg123, cv::Size(JBL_Detect->input_0.width, JBL_Detect->input_0.height)); + float fss = 0; + int rclass = JBL_Detect->AIClass(dealImg123, &fss); + printf("test ------------rclass %d score %f\n", rclass, fss); + // printf("%d %d\n", manager_1->BOE_Edge_Detect->m_img_In_0.width, manager_1->BOE_Edge_Detect->m_img_In_0.height); + + // std::string strModelPath = "/home/aidlux/BOE/UseModel/Edge_Big.engine"; + // std::string strModelPath_jbl = "/home/aidlux/BOE/UseModel/class_14.engine"; + // std::shared_ptr manager_1 = AIManagerBase::GetInstance(0); + // std::shared_ptr manager_2 = AIManagerBase::GetInstance(1); + // std::shared_ptr manager_3 = AIManagerBase::GetInstance(0); + + // std::cout << "manager_1 instance address: " << manager_1.get() << std::endl; + // std::cout << "manager_2 instance address: " << manager_2.get() << std::endl; + // std::cout << "manager_3 instance address: " << manager_3.get() << std::endl; + + // std::cout << "manager_1->BOE_Edge_Detect instance address: " << manager_1->BOE_Edge_Detect.get() << std::endl; + // std::cout << "manager_2->BOE_Edge_Detect instance address: " << manager_2->BOE_Edge_Detect.get() << std::endl; + // std::cout << "manager_3->BOE_Edge_Detect instance address: " << manager_3->BOE_Edge_Detect.get() << std::endl; + + // std::cout << "manager_1->JBL_Detect instance address: " << manager_1->JBL_Detect.get() << std::endl; + // std::cout << "manager_2->JBL_Detect instance address: " << manager_2->JBL_Detect.get() << std::endl; + // std::cout << "manager_3->JBL_Detect instance address: " << manager_3->JBL_Detect.get() << std::endl; + + // manager_1->BOE_Edge_Detect->Init(strModelPath); + // manager_2->BOE_Edge_Detect->Init(strModelPath); + // manager_3->BOE_Edge_Detect->Init(strModelPath); + + // manager_1->JBL_Detect->Init(strModelPath_jbl); + + // manager_2->JBL_Detect->Init(strModelPath_jbl); + + // manager_3->JBL_Detect->Init(strModelPath_jbl); + + // cv::Mat temimg = cv::imread("/home/aidlux/xwj/AI_SO_Test/data/img/20250319_192154_Main_0_2_L255_Org.tif", 0); + // cv::Mat dealImg; + // printf("%d %d\n", manager_1->BOE_Edge_Detect->m_img_In_0.width, manager_1->BOE_Edge_Detect->m_img_In_0.height); + + // if (manager_1->BOE_Edge_Detect) + // { + // cv::resize(temimg, dealImg, cv::Size(manager_1->BOE_Edge_Detect->m_img_In_0.width, manager_1->BOE_Edge_Detect->m_img_In_0.height)); + // cv::Mat outimg; + + // manager_1->BOE_Edge_Detect->AIDet(dealImg, outimg); + // manager_2->BOE_Edge_Detect->AIDet(dealImg, outimg); + + // { + // long t1 = getcurTime(); + // cv::Mat output; + // for (int i = 0; i < 500; ++i) + // { + // manager_1->BOE_Edge_Detect->AIDet(dealImg, output); + // } + // for (int i = 0; i < 500; ++i) + // { + // manager_1->BOE_Edge_Detect->AIDet(dealImg, output); + // } + // long t2 = getcurTime(); + + // std::cout << "run 1000 : " << t2 - t1 << " 毫秒" << std::endl; + // // cv::imwrite(name + "_output.jpg", output); + // // std::cout << "[" << name << "] done\n"; + // }; + + // long t1 = getcurTime(); + + // // Lambda 线程函数 + // auto run_detection = [](std::shared_ptr engine, const cv::Mat &input, const std::string &name) + // { + // cv::Mat output; + // for (int i = 0; i < 500; ++i) + // { + // engine->AIDet(input, output); + // } + // // cv::imwrite(name + "_output.jpg", output); + // // std::cout << "[" << name << "] done\n"; + // }; + + // // 启动两个线程 + // std::thread thread1(run_detection, manager_1->BOE_Edge_Detect, dealImg, "manager1"); + // std::thread thread2(run_detection, manager_1->BOE_Edge_Detect, dealImg, "manager3"); + + // // 等待线程结束 + // thread1.join(); + // thread2.join(); + + // // for (int i = 0; i < 1000; i++) + // // { + // // manager_1->BOE_Edge_Detect->AIDet(dealImg, outimg); + // // // manager_3->BOE_Edge_Detect->AIDet(dealImg, outimg); + // // } + + // long t2 = getcurTime(); + + // std::cout << "run 1000 = thread 2 * 500 耗时: " << t2 - t1 << " 毫秒" << std::endl; + + // cv::imwrite("dealImg.jpg", dealImg); + // cv::imwrite("outimg.jpg", outimg); + // } + + // cv::Mat dealImg123; + // cv::resize(temimg, dealImg123, cv::Size(manager_1->JBL_Detect->m_img_In_0.width, manager_1->JBL_Detect->m_img_In_0.height)); + // float fss = 0; + // int rclass = manager_1->JBL_Detect->AIClass(dealImg, &fss); + // long t11 = getcurTime(); + // rclass = manager_1->JBL_Detect->AIClass(dealImg, &fss); + // long t12 = getcurTime(); + // printf("test ------------rclass %d score %f------- time %ld\n", rclass, fss, t12 - t11); + + // printf("test ------------------- \n"); + getchar(); + return 0; +} diff --git a/AIEngineModule/include/AIModel_Impl.h b/AIEngineModule/include/AIModel_Impl.h new file mode 100644 index 0000000..ab4c872 --- /dev/null +++ b/AIEngineModule/include/AIModel_Impl.h @@ -0,0 +1,220 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:49:50 + * @LastEditTime: 2025-09-06 22:23:08 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/include/CamDeal.h + */ +#ifndef AIModel_Impl_H_ +#define AIModel_Impl_H_ + +#include +#include +#include +#include "NvInfer.h" +#include "cuda_runtime_api.h" +#include "AI_Factory.h" +#include "Engine.h" + +using namespace std; +// 模型输入输出最大允许的 节点数 +#define MAX_MODEL_NODE_NUM 5 + +class AIModel_Impl : public AIModel_Base +{ +public: + enum AI_Buffer_Type + { + AI_Buffer_Type_INPUT, + AI_Buffer_Type_OUTPUT, + AI_Buffer_Type_Count, + }; + // 模型节点参数 一个模型包括多个节点,输入 输出。 + struct Node_Config : public AI_Image + { + int type; + + std::string name; + int ucharsize; + int floatsize; + int datalength; + + Node_Config() + { + channel = 0; + width = 0; + height = 0; + type = AI_Buffer_Type_INPUT; + name = ""; + ucharsize = 0; + floatsize = 0; + datalength = 0; + } + + void copy(Node_Config tem) + { + this->type = tem.type; + this->channel = tem.channel; + this->width = tem.width; + this->height = tem.height; + this->name = tem.name; + this->ucharsize = tem.ucharsize; + this->floatsize = tem.floatsize; + this->datalength = tem.datalength; + } + void CalDataSize() + { + ucharsize = channel * width * height * sizeof(unsigned char); + floatsize = channel * width * height * sizeof(float); + datalength = channel * width * height; + } + }; + + // 流上的 节点参数信息。 + struct Stream_Node_Config + { + Node_Config nodeConfig; + void *gpu_buffers; + void *gpu_ImgData; // uchar + + float *cpu_floatData; + + Stream_Node_Config() + { + + gpu_buffers = NULL; + gpu_ImgData = NULL; + cpu_floatData = NULL; + } + ~Stream_Node_Config() + { + if (gpu_buffers != NULL) + { + cudaFree(gpu_buffers); + gpu_buffers = NULL; + } + + if (gpu_ImgData != NULL) + { + cudaFree(gpu_ImgData); + gpu_ImgData = NULL; + } + if (cpu_floatData != NULL) + { + delete cpu_floatData; + cpu_floatData = NULL; + } + } + }; + + // cuda上 一个流 包括的所有参数 + struct Cuda_Stream_Config + { + int nstreamIdx; + cudaStream_t stream; + std::unique_ptr context; + std::shared_ptr pstreamNode_input_0; + std::shared_ptr pstreamNode_input_1; + std::shared_ptr pstreamNode_output_0; + std::shared_ptr pstreamNode_output_1; + std::shared_ptr pstreamNode_output_2; + std::vector> streamConfigList; + Cuda_Stream_Config() + { + nstreamIdx = 0; + streamConfigList.clear(); + pstreamNode_input_0 = nullptr; + pstreamNode_input_1 = nullptr; + pstreamNode_output_0 = nullptr; + pstreamNode_output_1 = nullptr; + pstreamNode_output_2 = nullptr; + } + ~Cuda_Stream_Config() + { + + cudaStreamDestroy(stream); + } + }; + + // GPU 上封装的参数信息 + struct GPU_Engine + { + bool bsucc; // 是否初始化成功 + int nGPUIdx; // GPU id号 + std::shared_ptr engine; // AI 模型 引擎 + std::vector> cudaSteams; // 所有流 + GPU_Engine() + { + nGPUIdx = 0; + cudaSteams.clear(); + bsucc = false; + } + }; + // AI 检测 顺序调用 gpu stream 流。 + struct Det_GPU_Stram + { + std::mutex AI_mutex; + int nGPUIdx; + std::shared_ptr engine; // AI 模型 引擎 + + std::shared_ptr cuda_stream; + Det_GPU_Stram() + { + + nGPUIdx = 0; + } + }; + +public: + AIModel_Impl(); + ~AIModel_Impl(); + + // 初始化函数 + int Init(AIModelRun_Config config); + int AIDet(const cv::Mat &inImg, cv::Mat &outimg); + int AIDet(const cv::Mat &inImg, cv::Mat &outimg0, cv::Mat &outimg1); + int AIClass(const cv::Mat &inImg, float *fmaxScore); + +private: + // 运行参数检查 + int ModelRunConfigCheck(AIModelRun_Config &runConfig); + // 每个gpu 载入模型 + int LoadEngine(int ngpuIdx); + // 解析 模型的信息 + int GetEngineInfo1(std::shared_ptr &pgpuengine); + + int AI_Det_In_1_Out_1(Node_Config *pConfig_in, Node_Config *pConfig_out, const unsigned char *p_indata_0, unsigned char *p_outdata_1); + + int AI_Det_In_1_Out_1_class(unsigned char *p_indata_0, float *fmaxScore); + int F2softmaxId(float *data, int class_num, float *fmaxScore); + +private: + // 调用相关函数 + int GetStream(std::shared_ptr &pdetStream); + cv::Mat InitMat(int channel, int w, int h); + +private: + // 模型参数 + AIModelRun_Config m_modelRun_Config; + // 模型的输入输出list + std::vector m_modelNodeList; + + // 输入 输出节点 + Node_Config *m_pNode_input_0; + Node_Config *m_pNode_input_1; + Node_Config *m_pNode_output_0; + Node_Config *m_pNode_output_1; + Node_Config *m_pNode_output_2; + // 引擎列表,一个 gpu 一个引擎 + std::vector> m_GPU_Engine; + // 检测信息 + std::vector> m_DetGPUStream; + int m_nALLStreamNum; + +private: + // 上次使用的GPU stream Idx; + int m_nLast_GPUStreamIdx; +}; + +#endif \ No newline at end of file diff --git a/AIEngineModule/include/CUDA_DataChange.cuh b/AIEngineModule/include/CUDA_DataChange.cuh new file mode 100644 index 0000000..f0c7aed --- /dev/null +++ b/AIEngineModule/include/CUDA_DataChange.cuh @@ -0,0 +1,20 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:49:50 + * @LastEditTime: 2025-07-08 17:55:31 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/include/CamDeal.h + */ +#ifndef CUDA_Det_H_ +#define CUDA_Det_H_ +#include "cuda_runtime.h" +#include "cublas_v2.h" +#include "device_launch_parameters.h" +#include +#include + +void Cuda_ucharToFloat_stream(const unsigned char* input, float* output, int size, cudaStream_t stream); +void Cuda_FloatTouchar_stream(const float* input, unsigned char* output, int size, cudaStream_t stream); + +#endif \ No newline at end of file diff --git a/AIEngineModule/include/Engine.h b/AIEngineModule/include/Engine.h new file mode 100644 index 0000000..bce9da6 --- /dev/null +++ b/AIEngineModule/include/Engine.h @@ -0,0 +1,49 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-07-05 19:32:31 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-06 11:14:02 + * @FilePath: /AI_SO_Test/AIEngineModule/include/Engine.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ + +#ifndef Engine_H_ +#define Engine_H_ +#pragma once +#include +#include +#include +#include +#include +#include +using namespace nvinfer1; + +// 自定义删除器(确保正确释放TensorRT资源) +struct TensorRTDeleter +{ + void operator()(nvinfer1::IRuntime *ptr) const noexcept; + void operator()(nvinfer1::ICudaEngine *ptr) const noexcept; + void operator()(nvinfer1::IExecutionContext *ptr) const noexcept; // 添加上下文删除器 +}; +class Engine +{ +public: + Engine(int gpuId); + ~Engine(); + + bool loadFromFile(const std::string &enginePath); + int getNbBindings() const; + std::string getBindingName(int index) const; + nvinfer1::Dims getBindingDims(int index) const; + bool bindingIsInput(int index) const; + + nvinfer1::ICudaEngine *get() const { return engine_.get(); } + + std::mutex mutex_; + std::unique_ptr engine_; + +private: + int gpuId_; + std::unique_ptr runtime_; +}; +#endif \ No newline at end of file diff --git a/AIEngineModule/include_base/AI_Factory.h b/AIEngineModule/include_base/AI_Factory.h new file mode 100644 index 0000000..2fab0e2 --- /dev/null +++ b/AIEngineModule/include_base/AI_Factory.h @@ -0,0 +1,215 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-09-03 09:48:19 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-14 20:25:35 + * @FilePath: /AI_SO_Test/AIEngineModule/include_base/AI_Factory.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-07-04 14:41:18 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-03 10:27:59 + * @FilePath: /AI_SO_Test/AIEngineModule/include_base/AI_Engine_Base.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ + +#ifndef AI_Factory_H_ +#define AI_Factory_H_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +// GPU 可用信息 +struct GPU_Config +{ + bool gpu_0; + bool gpu_1; + GPU_Config() + { + gpu_0 = true; + gpu_1 = true; + } + int GetNum() + { + int num = 0; + if (gpu_0) + { + num++; + } + if (gpu_1) + { + num++; + } + return num; + } + void copy(GPU_Config tem) + { + this->gpu_0 = tem.gpu_0; + this->gpu_1 = tem.gpu_1; + } +}; + +// AI 模型 基础接口 +class AIModel_Base +{ +public: + enum Model_Input_Type + { + Input_NULL, + Input_HW, + Input_CHW, + Input_HWC, + }; + // 模型相关参数 + struct AIModelRun_Config + { + int Stream_num; // 流的个数 + bool IsClass; // 是分类 + std::string strPath; // 模型类型 + std::string strName; // 名称,别名 + Model_Input_Type inputType; // 数据格式类型 + GPU_Config gpuconfig; + AIModelRun_Config() + { + strPath = ""; + strName = ""; + inputType = Input_NULL; + Stream_num = 1; + IsClass = false; + } + void Copy(AIModelRun_Config tem) + { + this->Stream_num = tem.Stream_num; + this->strPath = tem.strPath; + this->strName = tem.strName; + this->inputType = tem.inputType; + this->IsClass = tem.IsClass; + this->gpuconfig.copy(tem.gpuconfig); + } + void print(std::string str) + { + printf("%s:Stream_num %d Path:%s inputType %d\n", str.c_str(), Stream_num, strPath.c_str(), inputType); + } + }; + + struct AI_Image + { + int channel; + int width; + int height; + AI_Image() + { + channel = 0; + width = 0; + height = 0; + } + void copy(AI_Image tem) + { + this->channel = tem.channel; + this->height = tem.height; + this->width = tem.width; + } + void print() + { + printf("[c w h] %d %d %d\n", channel, width, height); + } + }; + +public: + virtual ~AIModel_Base() = default; + + static std::shared_ptr GetInstance(); + // 初始化函数 + virtual int Init(AIModelRun_Config config) = 0; + virtual int AIDet(const cv::Mat &inImg, cv::Mat &outimg) = 0; + virtual int AIDet(const cv::Mat &inImg, cv::Mat &outimg0, cv::Mat &outimg1) = 0; + virtual int AIClass(const cv::Mat &inImg, float *fmaxScore) = 0; + +public: + bool m_bInitSuccess = false; + AI_Image input_0; + AI_Image input_1; + AI_Image output_0; + AI_Image output_1; + AI_Image output_2; +}; + +// 管理所有 模型 +class AIFactory +{ +public: + AIFactory(); + ~AIFactory(); + static std::shared_ptr GetInstance(); + // 初始化所有模型 + int InitALLAIModle(GPU_Config gupconfig); + +private: +public: + std::shared_ptr CELL_Mark; + std::shared_ptr CELL_Align; + + std::shared_ptr CELL_CA_Det; + std::shared_ptr CELL_TA_Det; + + std::shared_ptr CELL_CA_Cls; + std::shared_ptr CELL_TA_Cls; + +private: + // 模型是否都加载完成了。 + bool m_bInitSucc = false; +}; + +// 多线程推理 +class AIMulThreadRunBase +{ +public: + struct AITask + { + cv::Rect roi; + cv::Size srcroi; + int id; + cv::Mat input; + std::shared_ptr output; + std::shared_ptr engine; + bool bclass = false; + int cls_label = 0; + float cls_score = 0.0; + }; + +public: + AIMulThreadRunBase(); + ~AIMulThreadRunBase(); + + void Start(int num_threads = 2); + void Stop(); + + void SubmitTask(std::shared_ptr task); + bool PopResult(std::shared_ptr &result); + + // 新增接口,查询当前正在处理的任务数 + int GetProcessingCount() const { return m_processing_count_.load(); } + std::atomic m_detnum; // 当前正在执行任务数 +private: + void ThreadLoop(); + +private: + std::queue> m_tasks_; + std::queue> m_results_; + std::vector m_workers_; + std::mutex m_task_mutex_; + std::mutex m_result_mutex_; + std::mutex m_AI_mutex_; + std::condition_variable m_task_cv_; + std::atomic m_running_; + std::atomic m_processing_count_; // 当前正在执行任务数 +}; + +#endif \ No newline at end of file diff --git a/AIEngineModule/src/AIModel_Impl.cpp b/AIEngineModule/src/AIModel_Impl.cpp new file mode 100644 index 0000000..f90c263 --- /dev/null +++ b/AIEngineModule/src/AIModel_Impl.cpp @@ -0,0 +1,588 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-09-03 10:44:31 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-06 22:29:55 + * @FilePath: /AI_SO_Test/AIEngineModule/src/AIModel_Impl.cpp + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ + +#include "AIModel_Impl.h" +#include "CUDA_DataChange.cuh" +AIModel_Impl::AIModel_Impl() +{ + m_bInitSuccess = false; + m_GPU_Engine.clear(); + m_modelNodeList.clear(); + m_pNode_input_0 = NULL; + m_pNode_input_1 = NULL; + m_pNode_output_0 = NULL; + m_pNode_output_1 = NULL; + m_pNode_output_2 = NULL; + m_DetGPUStream.clear(); + m_nLast_GPUStreamIdx = 0; + m_nALLStreamNum = 0; +} +AIModel_Impl::~AIModel_Impl() +{ +} +int AIModel_Impl::Init(AIModelRun_Config config) +{ + m_modelRun_Config.Copy(config); + printf(">>> %s Init Start \n", m_modelRun_Config.strName.c_str()); + + if (m_bInitSuccess) + { + printf("strName %s Init Success %d ************ return \n", m_modelRun_Config.strName.c_str(), m_bInitSuccess); + return 0; + } + int re = 0; + re = ModelRunConfigCheck(m_modelRun_Config); + if (re != 0) + { + printf("strName %s Init Error =%d run Config error \n", m_modelRun_Config.strName.c_str(), re); + return re; + } + + // 不同显卡 单独 载入模型 + if (m_modelRun_Config.gpuconfig.gpu_0) + { + re = LoadEngine(0); + // 加载失败 + if (re != 0) + { + } + } + if (m_modelRun_Config.gpuconfig.gpu_1) + { + re = LoadEngine(1); + // 加载失败 + if (re != 0) + { + } + } + int nGPUNum = m_GPU_Engine.size(); + // 模型载入失败 + if (nGPUNum <= 0 || nGPUNum > 2) + { + printf(" %s model Init error \n", m_modelRun_Config.strName.c_str()); + return 2; + } + for (int i = 0; i < m_modelNodeList.size(); i++) + { + if (m_modelNodeList.at(i).type == AI_Buffer_Type_INPUT) + { + if (m_pNode_input_0 == NULL) + { + m_pNode_input_0 = &m_modelNodeList.at(i); + input_0.copy(*m_pNode_input_0); + } + else + { + m_pNode_input_1 = &m_modelNodeList.at(i); + input_1.copy(*m_pNode_input_1); + } + } + else + { + if (m_pNode_output_0 == NULL) + { + m_pNode_output_0 = &m_modelNodeList.at(i); + output_0.copy(*m_pNode_output_0); + } + else if (m_pNode_output_1 == NULL) + { + m_pNode_output_1 = &m_modelNodeList.at(i); + output_1.copy(*m_pNode_output_1); + } + else + { + m_pNode_output_2 = &m_modelNodeList.at(i); + output_2.copy(*m_pNode_output_2); + } + } + } + if (m_pNode_input_0 == NULL || m_pNode_output_0 == NULL) + { + printf(" %s model Init error \n", m_modelRun_Config.strName.c_str()); + return 3; + } + + int streamNum = m_GPU_Engine.at(0)->cudaSteams.size(); + + // 生产推理用的 参数信息 + if (m_GPU_Engine.size() > 1) + { + if (m_GPU_Engine.at(0)->cudaSteams.size() != m_GPU_Engine.at(1)->cudaSteams.size()) + { + printf(" %s model Init error \n", m_modelRun_Config.strName.c_str()); + return 3; + } + } + if (streamNum <= 0) + { + printf(" %s model Init streamNum error \n", m_modelRun_Config.strName.c_str()); + return 4; + } + + // 显示初始化信息 + if (true) + { + printf("Model Name :%s GUP engine Num %ld\n", m_modelRun_Config.strName.c_str(), m_GPU_Engine.size()); + + for (const auto &ge : m_GPU_Engine) + { + printf(" gpu %d status %d strem Num %ld \n", ge->nGPUIdx, ge->bsucc, ge->cudaSteams.size()); + + for (const auto &psteam : ge->cudaSteams) + { + printf(" steam %d \n", psteam->nstreamIdx); + for (const auto &pcon : psteam->streamConfigList) + { + printf(" type %d [chw] %d %d %d input %p output %p\n", + pcon->nodeConfig.type, pcon->nodeConfig.channel, pcon->nodeConfig.height, pcon->nodeConfig.width, + pcon->gpu_buffers, pcon->gpu_ImgData); + } + } + } + } + + // 把所有gup 的所有stream 都放到一起,方便调用。 + for (int i = 0; i < streamNum; i++) + { + + for (int igpu = 0; igpu < nGPUNum; igpu++) + { + std::shared_ptr temDetStream = std::make_shared(); + temDetStream->nGPUIdx = m_GPU_Engine.at(igpu)->nGPUIdx; + temDetStream->engine = m_GPU_Engine.at(igpu)->engine; + temDetStream->cuda_stream = m_GPU_Engine.at(igpu)->cudaSteams.at(i); + m_DetGPUStream.push_back(temDetStream); + } + } + m_nALLStreamNum = m_DetGPUStream.size(); + printf("========********* Model Name :%s GUP engine Num %ld **************=============\n", m_modelRun_Config.strName.c_str(), m_GPU_Engine.size()); + for (const auto steam : m_DetGPUStream) + { + printf(">>> gpu %d stream %d \n", + steam->nGPUIdx, steam->cuda_stream->nstreamIdx); + } + + m_bInitSuccess = true; + return 0; +} +cv::Mat AIModel_Impl::InitMat(int channel, int w, int h) +{ + if (w <= 0 || h <= 0 || channel <= 0 || channel > 3) + { + return cv::Mat(); + } + + cv::Mat dst; + if (channel == 1) + { + dst = cv::Mat(h, w, CV_8UC1, cv::Scalar(0)); + } + else + { + dst = cv::Mat(h, w, CV_8UC3, cv::Scalar(0, 0, 0)); + } + return dst; +} +int AIModel_Impl::AIDet(const cv::Mat &inImg, cv::Mat &outimg) +{ + + // 1、准备数据 + if (m_pNode_input_0 == NULL || m_pNode_output_0 == NULL) + { + printf("AIDet: Node Config INput output Node error \n"); + return 1; + } + // std::this_thread::sleep_for(std::chrono::milliseconds(2)); // Sleep for 100 milliseconds + uchar *p_indata_0 = (uchar *)inImg.data; + outimg = InitMat(m_pNode_output_0->channel, m_pNode_output_0->width, m_pNode_output_0->height); + uchar *p_outdata_1 = (uchar *)outimg.data; + if (!m_bInitSuccess) + { + return 2; + } + + AI_Det_In_1_Out_1(m_pNode_input_0, m_pNode_output_0, p_indata_0, p_outdata_1); + return 0; +} + +int AIModel_Impl::AIDet(const cv::Mat &inImg, cv::Mat &outimg0, cv::Mat &outimg1) +{ + return 0; +} + +int AIModel_Impl::AIClass(const cv::Mat &inImg, float *fmaxScore) +{ + // 1、准备数据 + if (m_pNode_input_0 == NULL || m_pNode_output_0 == NULL) + { + printf("AIDet: Node Config INput output Node error \n"); + return -1; + } + if (!m_bInitSuccess) + { + return -2; + } + uchar *p_indata_0 = (uchar *)inImg.data; + + int class_dix = 0; + class_dix = AI_Det_In_1_Out_1_class(p_indata_0, fmaxScore); + + return class_dix; +} + +// 检测模型的运行参数是否合法,是否正常 +int AIModel_Impl::ModelRunConfigCheck(AIModelRun_Config &runConfig) +{ + // GPU 数量判断 + if (runConfig.gpuconfig.GetNum() == 0) + { + return 1; + } + if (runConfig.strPath == "") + { + printf(" %s model path is error \n", runConfig.strName.c_str()); + return 2; + } + if (runConfig.Stream_num <= 0) + { + runConfig.Stream_num = 1; + } + if (runConfig.Stream_num > 4) + { + runConfig.Stream_num = 4; + } + + return 0; +} + +// 载入模型。。。。 +int AIModel_Impl::LoadEngine(int ngpuIdx) +{ + std::shared_ptr gpuEngine = std::make_shared(); + gpuEngine->engine = std::make_shared(ngpuIdx); + gpuEngine->nGPUIdx = ngpuIdx; + if (!gpuEngine->engine) + { + printf("Engine Create error\n"); + return -1; + } + // 1、加载模型 + bool reload = gpuEngine->engine->loadFromFile(m_modelRun_Config.strPath); + + if (!reload) + { + printf("GPU %d Load error %s\n", ngpuIdx, m_modelRun_Config.strPath.c_str()); + printf("Load model error\n"); + return -2; + } + printf("%s GPU %d Load succ %s\n", m_modelRun_Config.strName.c_str(), ngpuIdx, m_modelRun_Config.strPath.c_str()); + + // 2、 解析 egengine的 相关信息 + int re = GetEngineInfo1(gpuEngine); + if (re != 0) + { + return re; + } + // 没有输入输出 节点。 + if (m_modelNodeList.size() <= 0 || m_modelNodeList.size() > MAX_MODEL_NODE_NUM) + { + printf("Load model input output error\n"); + return -3; + } + + cudaSetDevice(ngpuIdx); + // 3、 申请显存 + for (int i = 0; i < m_modelRun_Config.Stream_num; i++) + { + std::shared_ptr cudasteam = std::make_shared(); + cudasteam->nstreamIdx = i; + + if (cudaStreamCreate(&cudasteam->stream) != cudaSuccess) + { + printf("Failed to create CUDA stream\n"); + return -4; + } + cudasteam->context = std::unique_ptr( + gpuEngine->engine->engine_->createExecutionContext()); + // printf("----- stream %d \n", i); + // 初始化 数据 内存 + for (int j = 0; j < m_modelNodeList.size(); j++) + { + std::shared_ptr steamNodeconfig = std::make_shared(); + steamNodeconfig->nodeConfig.copy(m_modelNodeList.at(j)); + + cudaMalloc(&steamNodeconfig->gpu_buffers, steamNodeconfig->nodeConfig.floatsize); + cudaMalloc(&steamNodeconfig->gpu_ImgData, steamNodeconfig->nodeConfig.ucharsize); + // 分类 的模型 + if (m_modelRun_Config.IsClass) + { + if (steamNodeconfig->cpu_floatData) + { + delete steamNodeconfig->cpu_floatData; + steamNodeconfig->cpu_floatData = NULL; + } + + steamNodeconfig->cpu_floatData = new float[steamNodeconfig->nodeConfig.datalength]; + } + + printf("-----******GPU %d stream %d cuda malloc %d inOrout %d [chw] %d*%d*%d \n", + ngpuIdx, i, j, steamNodeconfig->nodeConfig.type, steamNodeconfig->nodeConfig.channel, + steamNodeconfig->nodeConfig.height, steamNodeconfig->nodeConfig.width); + + if (m_modelNodeList.at(j).type == AI_Buffer_Type_INPUT) + { + if (cudasteam->pstreamNode_input_0 == nullptr) + { + cudasteam->pstreamNode_input_0 = steamNodeconfig; + } + else + { + cudasteam->pstreamNode_input_1 = steamNodeconfig; + } + } + else + { + if (cudasteam->pstreamNode_output_0 == nullptr) + { + cudasteam->pstreamNode_output_0 = steamNodeconfig; + } + else if (cudasteam->pstreamNode_output_1 == nullptr) + { + cudasteam->pstreamNode_output_1 = steamNodeconfig; + } + else + { + cudasteam->pstreamNode_output_2 = steamNodeconfig; + } + } + cudasteam->streamConfigList.push_back(steamNodeconfig); + } + gpuEngine->cudaSteams.push_back(cudasteam); + } + gpuEngine->bsucc = true; + + m_GPU_Engine.push_back(gpuEngine); + + return 0; +} + +int AIModel_Impl::GetEngineInfo1(std::shared_ptr &pgpuengine) +{ + int nInputNum = pgpuengine->engine->getNbBindings(); + + m_modelNodeList.erase(m_modelNodeList.begin(), m_modelNodeList.end()); + m_modelNodeList.clear(); + + for (int i = 0; i < nInputNum; i++) + { + Node_Config node_config; + + std::string name = pgpuengine->engine->getBindingName(i); + node_config.name = name; + Dims dims = pgpuengine->engine->getBindingDims(i); + + if (pgpuengine->engine->bindingIsInput(i)) + { + std::cout << "Input: " << name << "\n"; + node_config.type = AI_Buffer_Type_INPUT; + } + else + { + std::cout << "Output: " << name << "\n"; + node_config.type = AI_Buffer_Type_OUTPUT; + } + std::cout << "dims.nbDims: " << dims.nbDims << "\n"; + if (dims.nbDims == 4) + { + + switch (m_modelRun_Config.inputType) + { + case Input_CHW: + node_config.channel = dims.d[1]; + node_config.height = dims.d[2]; + node_config.width = dims.d[3]; + break; + case Input_HWC: + + node_config.height = dims.d[1]; + node_config.width = dims.d[2]; + node_config.channel = dims.d[3]; + break; + default: + node_config.channel = dims.d[1]; + node_config.height = dims.d[2]; + node_config.width = dims.d[3]; + break; + } + } + else if (dims.nbDims == 3) + { + switch (m_modelRun_Config.inputType) + { + case Input_CHW: + node_config.channel = dims.d[0]; + node_config.height = dims.d[1]; + node_config.width = dims.d[2]; + break; + case Input_HWC: + + node_config.height = dims.d[0]; + node_config.width = dims.d[1]; + node_config.channel = dims.d[2]; + break; + default: + node_config.channel = dims.d[0]; + node_config.height = dims.d[1]; + node_config.width = dims.d[2]; + break; + } + } + else if (dims.nbDims == 2) + { + node_config.channel = 1; + node_config.height = dims.d[0]; + node_config.width = dims.d[1]; + } + else if (dims.nbDims == 1) + { + node_config.channel = 1; + node_config.height = dims.d[0]; + node_config.width = 1; + } + else + { + printf("engine C H W is error\n"); + return -2; + } + node_config.CalDataSize(); + + m_modelNodeList.push_back(node_config); + printf("dim: "); + for (int di = 0; di < dims.nbDims; di++) + { + printf(" %ld ", dims.d[di]); + } + printf(" \n"); + printf("C H W [%d %d %d]\n", node_config.channel, node_config.height, node_config.width); + } + + return 0; +} + +int AIModel_Impl::AI_Det_In_1_Out_1(Node_Config *pConfig_in, Node_Config *pConfig_out, const unsigned char *p_indata_0, unsigned char *p_outdata_1) +{ + // printf("=== s1 "); + std::shared_ptr pdetStream; + GetStream(pdetStream); + // printf("=== s2 "); + std::lock_guard lock(pdetStream->AI_mutex); + // printf(" ss g %d s %d -- ", pdetStream->nGPUIdx, pdetStream->cuda_stream->nstreamIdx); + // // 设置 显卡ID + cudaSetDevice(pdetStream->nGPUIdx); + + cudaMemcpyAsync(pdetStream->cuda_stream->pstreamNode_input_0->gpu_ImgData, + p_indata_0, pConfig_in->ucharsize, cudaMemcpyHostToDevice, pdetStream->cuda_stream->stream); + // // // 在显存中 图片数据从 uchar 转到 float + Cuda_ucharToFloat_stream((unsigned char *)pdetStream->cuda_stream->pstreamNode_input_0->gpu_ImgData, + (float *)pdetStream->cuda_stream->pstreamNode_input_0->gpu_buffers, pConfig_in->datalength, pdetStream->cuda_stream->stream); + + pdetStream->cuda_stream->context->setTensorAddress(pConfig_in->name.c_str(), pdetStream->cuda_stream->pstreamNode_input_0->gpu_buffers); + pdetStream->cuda_stream->context->setTensorAddress(pConfig_out->name.c_str(), pdetStream->cuda_stream->pstreamNode_output_0->gpu_buffers); + + pdetStream->cuda_stream->context->enqueueV3(pdetStream->cuda_stream->stream); + + Cuda_FloatTouchar_stream((float *)pdetStream->cuda_stream->pstreamNode_output_0->gpu_buffers, + (unsigned char *)pdetStream->cuda_stream->pstreamNode_output_0->gpu_ImgData, pConfig_out->datalength, pdetStream->cuda_stream->stream); + cudaMemcpyAsync(p_outdata_1, pdetStream->cuda_stream->pstreamNode_output_0->gpu_ImgData, + pConfig_out->ucharsize, cudaMemcpyDeviceToHost, pdetStream->cuda_stream->stream); + cudaStreamSynchronize(pdetStream->cuda_stream->stream); + // printf("**ee g %d s %d ** \n", pdetStream->nGPUIdx, pdetStream->cuda_stream->nstreamIdx); + return 0; +} + +int AIModel_Impl::GetStream(std::shared_ptr &pdetStream) +{ + int sidx = m_nLast_GPUStreamIdx; + + sidx++; + if (sidx >= m_nALLStreamNum) + { + sidx = 0; + } + pdetStream = m_DetGPUStream.at(sidx); + m_nLast_GPUStreamIdx = sidx; + + return 0; +} +int AIModel_Impl::AI_Det_In_1_Out_1_class(unsigned char *p_indata_0, float *fmaxScore) +{ + std::shared_ptr pdetStream; + GetStream(pdetStream); + // printf("=== s2 "); + std::lock_guard lock(pdetStream->AI_mutex); + // printf(" ss g %d s %d -- ", pdetStream->nGPUIdx, pdetStream->cuda_stream->nstreamIdx); + // // 设置 显卡ID + std::shared_ptr p_input_0 = pdetStream->cuda_stream->pstreamNode_input_0; + std::shared_ptr p_output_0 = pdetStream->cuda_stream->pstreamNode_output_0; + cudaSetDevice(pdetStream->nGPUIdx); + + cudaMemcpyAsync(p_input_0->gpu_ImgData, p_indata_0, + p_input_0->nodeConfig.ucharsize, cudaMemcpyHostToDevice, pdetStream->cuda_stream->stream); + // // // 在显存中 图片数据从 uchar 转到 float + Cuda_ucharToFloat_stream((unsigned char *)p_input_0->gpu_ImgData, + (float *)p_input_0->gpu_buffers, p_input_0->nodeConfig.datalength, pdetStream->cuda_stream->stream); + + pdetStream->cuda_stream->context->setTensorAddress(p_input_0->nodeConfig.name.c_str(), p_input_0->gpu_buffers); + pdetStream->cuda_stream->context->setTensorAddress(p_output_0->nodeConfig.name.c_str(), p_output_0->gpu_buffers); + + pdetStream->cuda_stream->context->enqueueV3(pdetStream->cuda_stream->stream); + + cudaMemcpyAsync(p_output_0->cpu_floatData, p_output_0->gpu_buffers, + p_output_0->nodeConfig.floatsize, cudaMemcpyDeviceToHost, pdetStream->cuda_stream->stream); + cudaStreamSynchronize(pdetStream->cuda_stream->stream); + + int label = F2softmaxId(p_output_0->cpu_floatData, p_output_0->nodeConfig.datalength, fmaxScore); + return label; +} +int AIModel_Impl::F2softmaxId(float *data, int class_num, float *fmaxScore) +{ + int cls_num = class_num; + float total = 0; + for (int i = 0; i < cls_num; i++) + { + // std::cout<<"data["< +#include +#include +long getcurTime4444() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return ((long)tv.tv_sec) * 1000 + ((long)tv.tv_usec) / 1000; +} +AIMulThreadRunBase::AIMulThreadRunBase() : m_running_(false), m_processing_count_(0) {} + +AIMulThreadRunBase::~AIMulThreadRunBase() +{ + Stop(); +} + +void AIMulThreadRunBase::Start(int num_threads) +{ + if (m_running_) + return; + m_running_ = true; + m_detnum = 0; + // num_threads = 2; + // 仅启动1个线程 + for (int i = 0; i < num_threads; ++i) + { + m_workers_.emplace_back(&AIMulThreadRunBase::ThreadLoop, this); + } +} + +void AIMulThreadRunBase::Stop() +{ + m_running_ = false; + m_task_cv_.notify_all(); + for (auto &t : m_workers_) + { + if (t.joinable()) + t.join(); + } + m_workers_.clear(); +} + +void AIMulThreadRunBase::SubmitTask(std::shared_ptr task) +{ + { + std::lock_guard lock(m_task_mutex_); + m_tasks_.push(task); + } + m_processing_count_++; + m_task_cv_.notify_one(); +} + +bool AIMulThreadRunBase::PopResult(std::shared_ptr &result) +{ + std::lock_guard lock(m_result_mutex_); + if (m_results_.empty()) + return false; + result = m_results_.front(); + m_results_.pop(); + return true; +} + +void AIMulThreadRunBase::ThreadLoop() +{ + while (m_running_) + { + + std::shared_ptr task; + { + std::unique_lock lock(m_task_mutex_); + m_task_cv_.wait(lock, [this]() + { return !m_tasks_.empty() || !m_running_; }); + + if (!m_running_ && m_tasks_.empty()) + return; + + task = std::move(m_tasks_.front()); + m_tasks_.pop(); + } + if (task->bclass) + { + // 执行推理 + if (task->engine) + { + // std::lock_guard lock(m_AI_mutex_); + // long t1 = getcurTime4444(); + task->cls_label = task->engine->AIClass(task->input, &task->cls_score); + // long t2 = getcurTime4444(); + // printf("det time %d m_tasks_ size %ld\n", t2 - t1,m_tasks_.size()); + } + } + else + { + // 执行推理 + if (task->engine && task->output) + { + // std::lock_guard lock(m_AI_mutex_); + // long t1 = getcurTime4444(); + task->engine->AIDet(task->input, *task->output); + // long t2 = getcurTime4444(); + // printf("det time %d m_tasks_ size %ld\n", t2 - t1,m_tasks_.size()); + } + } + { + std::lock_guard lock(m_result_mutex_); + m_results_.push(task); + } + // m_detnum++; + m_processing_count_--; + } +} \ No newline at end of file diff --git a/AIEngineModule/src/AI_Factory.cpp b/AIEngineModule/src/AI_Factory.cpp new file mode 100644 index 0000000..cb88e9a --- /dev/null +++ b/AIEngineModule/src/AI_Factory.cpp @@ -0,0 +1,106 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-09-03 10:33:48 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-14 20:28:10 + * @FilePath: /AI_SO_Test/AIEngineModule/src/AI_Factory.cpp + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#include "AI_Factory.h" + +#include "AIModel_Impl.h" + +std::shared_ptr AIModel_Base::GetInstance() +{ + std::shared_ptr instance = std::make_shared(); + return instance; +} + +AIFactory::AIFactory() +{ +} + +AIFactory::~AIFactory() +{ +} +std::shared_ptr AIFactory::GetInstance() +{ + static std::shared_ptr instance = std::make_shared(); + return instance; +} + +int AIFactory::InitALLAIModle(GPU_Config gupconfig) +{ + if (gupconfig.GetNum() == 0) + { + printf("GPU Num Error \n"); + return 1; + } + + if (!CELL_CA_Det) + { + CELL_CA_Det = AIModel_Base::GetInstance(); + AIModel_Base::AIModelRun_Config edge_config; + edge_config.gpuconfig.copy(gupconfig); + edge_config.strPath = "/home/aidlux/BOE/UseModel_CellAOI/Detect_CA.engine"; + edge_config.strName = "CA_Det"; + edge_config.inputType = AIModel_Base::Input_HWC; + edge_config.Stream_num = 2; + CELL_CA_Det->Init(edge_config); + } + if (!CELL_TA_Det) + { + CELL_TA_Det = AIModel_Base::GetInstance(); + AIModel_Base::AIModelRun_Config edge_config; + edge_config.gpuconfig.copy(gupconfig); + edge_config.strPath = "/home/aidlux/BOE/UseModel_CellAOI/Detect_TA.engine"; + edge_config.strName = "TA_Det"; + edge_config.inputType = AIModel_Base::Input_HWC; + edge_config.Stream_num = 2; + CELL_TA_Det->Init(edge_config); + } + if (!CELL_Align) + { + CELL_Align = AIModel_Base::GetInstance(); + AIModel_Base::AIModelRun_Config edge_config; + edge_config.gpuconfig.copy(gupconfig); + edge_config.strPath = "/home/aidlux/BOE/UseModel_CellAOI/Align.engine"; + edge_config.strName = "Align"; + edge_config.inputType = AIModel_Base::Input_HWC; + CELL_Align->Init(edge_config); + } + if (!CELL_Mark) + { + CELL_Mark = AIModel_Base::GetInstance(); + AIModel_Base::AIModelRun_Config edge_config; + edge_config.gpuconfig.copy(gupconfig); + edge_config.strPath = "/home/aidlux/BOE/UseModel_CellAOI/Cell_marker.engine"; + edge_config.strName = "Mark"; + edge_config.inputType = AIModel_Base::Input_HWC; + CELL_Mark->Init(edge_config); + } + if (!CELL_CA_Cls) + { + CELL_CA_Cls = AIModel_Base::GetInstance(); + AIModel_Base::AIModelRun_Config jbl_config; + jbl_config.gpuconfig.copy(gupconfig); + jbl_config.strPath = "/home/aidlux/BOE/UseModel_CellAOI/Class_10.engine"; + jbl_config.inputType = AIModel_Base::Input_HWC; + jbl_config.strName = "CA_Class"; + jbl_config.IsClass = true; + CELL_CA_Cls->Init(jbl_config); + } + if (!CELL_TA_Cls) + { + CELL_TA_Cls = AIModel_Base::GetInstance(); + AIModel_Base::AIModelRun_Config jbl_config; + jbl_config.gpuconfig.copy(gupconfig); + jbl_config.strPath = "/home/aidlux/BOE/UseModel_CellAOI/Class_10_TA.engine"; + jbl_config.inputType = AIModel_Base::Input_HWC; + jbl_config.strName = "TA_Class"; + jbl_config.IsClass = true; + CELL_TA_Cls->Init(jbl_config); + } + m_bInitSucc = true; + return 0; +} diff --git a/AIEngineModule/src/CUDA_DataChange.cu b/AIEngineModule/src/CUDA_DataChange.cu new file mode 100644 index 0000000..035b341 --- /dev/null +++ b/AIEngineModule/src/CUDA_DataChange.cu @@ -0,0 +1,34 @@ + +#include "CUDA_DataChange.cuh" + +__global__ void ucharToFloat_stream(const unsigned char *input, float *output, int size) +{ + int tid = blockIdx.x * blockDim.x + threadIdx.x; + if (tid < size) + { + output[tid] = static_cast(input[tid]); + } +} +__global__ void floatToUchar_stream(const float *input, unsigned char *output, int size) +{ + int tid = blockIdx.x * blockDim.x + threadIdx.x; + if (tid < size) + { + output[tid] = static_cast(input[tid]); + } +} + +void Cuda_ucharToFloat_stream(const unsigned char *input, float *output, int size, cudaStream_t stream) +{ + int blockSize = 1024; + int numBlocks = (size + blockSize - 1) / blockSize; + ucharToFloat_stream<<>>(input, output, size); +} + +void Cuda_FloatTouchar_stream(const float *input, unsigned char *output, int size, cudaStream_t stream) +{ + + int blockSize = 1024; + int numBlocks = (size + blockSize - 1) / blockSize; + floatToUchar_stream<<>>(input, output, size); +} diff --git a/AIEngineModule/src/Engine.cpp b/AIEngineModule/src/Engine.cpp new file mode 100644 index 0000000..5de8c8c --- /dev/null +++ b/AIEngineModule/src/Engine.cpp @@ -0,0 +1,157 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-07-05 19:32:41 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-06 11:13:54 + * @FilePath: /AI_SO_Test/AIEngineModule/src/Engine.cpp + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#include "Engine.h" + +#include +#include +#include + +using namespace nvinfer1; + +class Logger : public ILogger +{ +public: + void log(Severity severity, const char *msg) noexcept override + { + if (severity <= Severity::kWARNING) + std::cout << "[TensorRT] " << msg << std::endl; + } +} gLogger; +// 实现自定义删除器 +void TensorRTDeleter::operator()(nvinfer1::IRuntime *ptr) const noexcept +{ + // if (ptr) + // { + // printf("************ IRuntime \n"); + // // delete ptr; + // } +} +void TensorRTDeleter::operator()(nvinfer1::IExecutionContext *ptr) const noexcept +{ + // if (!ptr) + // return; + + // try + // { + // printf("************ IExecutionContext \n"); + // // 检查有效性、上下文等 + // delete ptr; + // } + // catch (const std::exception &e) + // { + // std::cerr << "[Deleter] Exception: " << e.what() << "\n"; + // } + // catch (...) + // { + // std::cerr << "[Deleter] Unknown error during deletion\n"; + // } +} +void TensorRTDeleter::operator()(nvinfer1::ICudaEngine *ptr) const noexcept +{ + // if (ptr) + // { + // printf("************ ICudaEngine \n"); + // delete ptr; + // } + // if (ptr) + // { + // printf("************ ICudaEngine \n"); + // try + // { + // // delete ptr; // + // } + // catch (...) + // { + // std::cerr << "[Deleter] Exception deleting ICudaEngine\n"; + // } + // } +} +Engine::Engine(int gpuId) : gpuId_(gpuId) {} + +Engine::~Engine() +{ + // printf("========Engine= start ====\n"); + // engine_.reset(); + // runtime_.reset(); + // printf("========Engine= engine_.reset();====\n"); +} + +bool Engine::loadFromFile(const std::string &enginePath) +{ + + try + { + cudaSetDevice(gpuId_); + std::ifstream file(enginePath, std::ios::binary); + if (!file) + { + std::cerr << "[Engine] Failed to open engine file: " << enginePath << std::endl; + return false; + } + + file.seekg(0, file.end); + size_t size = file.tellg(); + file.seekg(0, file.beg); + std::vector engineData(size); + file.read(engineData.data(), size); + runtime_ = std::unique_ptr(createInferRuntime(gLogger)); + if (!runtime_) + { + std::cerr << "[Engine] Failed to create runtime." << std::endl; + return false; + } + + engine_ = std::unique_ptr( + runtime_->deserializeCudaEngine(engineData.data(), size)); + + if (!engine_) + { + std::cerr << "[Engine] Failed to deserialize engine." << std::endl; + return false; + } + + return true; + } + catch (const std::exception &e) + { + std::cerr << "[Engine] Exception during loadFromFile: " << e.what() << std::endl; + return false; + } + catch (...) + { + std::cerr << "[Engine] Unknown exception during loadFromFile." << std::endl; + return false; + } +} + +int Engine::getNbBindings() const +{ + return engine_ ? engine_->getNbIOTensors() : 0; +} + +std::string Engine::getBindingName(int index) const +{ + return engine_ ? engine_->getIOTensorName(index) : ""; +} + +Dims Engine::getBindingDims(int index) const +{ + if (!engine_) + return Dims{}; + std::string name = engine_->getIOTensorName(index); + return engine_->getTensorShape(name.c_str()); +} + +bool Engine::bindingIsInput(int index) const +{ + if (!engine_) + return false; + std::string name = engine_->getIOTensorName(index); + return engine_->getTensorIOMode(name.c_str()) == TensorIOMode::kINPUT; +} \ No newline at end of file diff --git a/AlgorithmModule/CMakeLists.txt b/AlgorithmModule/CMakeLists.txt new file mode 100644 index 0000000..f6299c7 --- /dev/null +++ b/AlgorithmModule/CMakeLists.txt @@ -0,0 +1,88 @@ +cmake_minimum_required (VERSION 3.5) + +set(ModuleName "TY_CheckModule") + + +#==============TensorRT 版本控制==================== +# 查找 TensorRT 的头文件路径 +find_path(TENSORRT_INCLUDE_DIR + NAMES NvInfer.h + PATHS /usr/include/x86_64-linux-gnu /usr/local/include +) + +if(NOT TENSORRT_INCLUDE_DIR) + message(FATAL_ERROR "TensorRT headers not found") +endif() + +message(STATUS "TENSORRT_INCLUDE_DIR: " ${TENSORRT_INCLUDE_DIR}) + +# 提取版本号 +file(READ "${TENSORRT_INCLUDE_DIR}/NvInferVersion.h" TENSORRT_VERSION_CONTENTS) +string(REGEX MATCH "#define NV_TENSORRT_MAJOR ([0-9]+)" _ ${TENSORRT_VERSION_CONTENTS}) +set(TRT_MAJOR_VERSION ${CMAKE_MATCH_1}) +message(STATUS "Found TensorRT v${TRT_MAJOR_VERSION}") +# 检查版本 +if(TRT_MAJOR_VERSION VERSION_LESS 10) + message(STATUS " close //#define USE_TERNSORRT10_BIGMODEL") +else() +add_definitions(-DUSE_TERNSORRT10_BIGMODEL=${TEST_VALUE}) + message(STATUS "#define USE_TERNSORRT10_BIGMODEL") + +endif() + +#==============TensorRT 版本控制==================== + +set(CMAKE_CXX_FLAGS "-Wno-error=deprecated-declarations -Wno-deprecated-declarations") +find_package(CUDA REQUIRED) +message(STATUS "cuda version: " ${CUDA_VERSION_STRING}) +message(STATUS "cuda CUDA_INCLUDE_DIRS: " ${CUDA_INCLUDE_DIRS}) +include_directories(${CUDA_INCLUDE_DIRS}) +include_directories( +/usr/include +#/usr/local/cuda-11.3/targets/x86_64-linux/include +${CMAKE_CURRENT_SOURCE_DIR}/include +${PROJECT_SOURCE_DIR}/include/TensorRT +${PROJECT_SOURCE_DIR}/ConfigModule/include +${PROJECT_SOURCE_DIR}/Common/include +${PROJECT_SOURCE_DIR}/AIEngineModule/include +${PROJECT_SOURCE_DIR}/AIEngineModule/include_base +) +link_directories( +/usr/local/lib/ +) +set(CMAKE_CUDA_ARCHITECTURES 86) +set(CMAKE_CUDA_COMPILER "/usr/local/cuda/bin/nvcc") +enable_language(CUDA) +# 用set设置变量不能使用*.cpp +file(GLOB SRC_LISTS + ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cu + ${PROJECT_SOURCE_DIR}/AIEngineModule/src/*.cpp + ${PROJECT_SOURCE_DIR}/AIEngineModule/src/*.c + ${PROJECT_SOURCE_DIR}/AIEngineModule/src/*.cu +) +add_library(TY_Check SHARED ${SRC_LISTS}) + +target_link_libraries(TY_Check + nvinfer + Config + ${OpenCV_LIBS} + ${CUDA_LIBRARIES} + ) +set(ModuleName "") + + + +# make install 安装到/usr/local下 +# 自定义安装前缀 +set(CMAKE_INSTALL_PREFIX /usr/local/cellAOI CACHE PATH "Install path prefix" FORCE) +set(HEADER_FILES include/ImgCheckBase.h include/ImgCheckConfig.h) +# 安装动态库 +install(TARGETS TY_Check + LIBRARY DESTINATION lib # 安装到 CMAKE_INSTALL_PREFIX/lib + ARCHIVE DESTINATION lib/static + RUNTIME DESTINATION bin + PUBLIC_HEADER DESTINATION include) # 安装到 CMAKE_INSTALL_PREFIX/include +# 安装头文件 +install(FILES ${HEADER_FILES} DESTINATION include) \ No newline at end of file diff --git a/AlgorithmModule/include/AICommonDefine.h b/AlgorithmModule/include/AICommonDefine.h new file mode 100644 index 0000000..58e3caa --- /dev/null +++ b/AlgorithmModule/include/AICommonDefine.h @@ -0,0 +1,43 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:49:50 + * @LastEditTime: 2025-09-17 19:09:40 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/include/CamDeal.h + */ +#ifndef AICommonDefine_H_ +#define AICommonDefine_H_ + +// AI缺陷分类缺陷的种类 +enum AI_CLass_QX_NAME_ +{ + + AI_CLass_QX_NAME_aotudian, // 凹凸点 + AI_CLass_QX_NAME_other, // 其他 + AI_CLass_QX_NAME_line, // 线状 + AI_CLass_QX_NAME_zangwu, // 脏污 + AI_CLass_QX_NAME_dianzhuang, // 点状 + AI_CLass_QX_NAME_posun, // 破损 + AI_CLass_QX_NAME_xianwei, // 纤维 + AI_CLass_QX_NAME_shuizi, // 水渍 + AI_CLass_QX_NAME_danban, // 淡斑 + AI_CLass_QX_NAME_fuchen, // 浮尘 + AI_CLass_QX_NAME_count, +}; +// 缺陷项对应在参数中的名称 +static const std::string AI_CLass_QX_NAME_Names[] = + { + "aotudian", + "qx", + "line", + "zangwu", + "dianzhuang", + "posun", + "xianwei", + "shuizi", + "danban", + "fuchen", + }; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/AI_Edge_Algin.h b/AlgorithmModule/include/AI_Edge_Algin.h new file mode 100644 index 0000000..7fb9e3a --- /dev/null +++ b/AlgorithmModule/include/AI_Edge_Algin.h @@ -0,0 +1,236 @@ +/* +//实现对部分缺陷 需要进行 数量 和距离上分析的 + */ +#ifndef AI_Edge_Algin_H_ +#define AI_Edge_Algin_H_ +#include +#include "CheckUtil.hpp" +#include "OtherDetBaseDefine.h" +#include "CheckErrorCodeDefine.hpp" +#include "ImageDetConfig.h" +#include "CheckConfigDefine.h" +#include "ImageStorage.h" +#include "AI_Factory.h" +#include "DetLog.h" +using namespace std; + +using namespace std; +using namespace cv; + +class AI_Edge_Algin +{ +public: + enum Mark_Result_Status + { + Mark_Result_Status_NULL, + Mark_Result_Status_OK, + Mark_Result_Status_Error, + }; + struct MarK_Result + { + Mark_Result_Status status; + cv::Rect SearchROI_DetImg; // 相对于 检测图的 搜索区域; + cv::Point param_Local_DetImg; // mark的参数位置,相对于检测图片 + cv::Point det_Local_DetImg; // 检测结果 相对于 检测图片 + + cv::Rect SearchROI_SrcImg; // 相对于 检测图的 搜索区域; + cv::Point param_Local_SrcImg; // mark的参数位置,相对于检测图片 + cv::Point det_Local_SrcImg; // 检测结果 相对于 检测图片 + MarK_Result() + { + status = Mark_Result_Status_NULL; + SearchROI_DetImg = cv::Rect(0, 0, 0, 0); + param_Local_DetImg = cv::Point(0, 0); + det_Local_DetImg = cv::Point(0, 0); + + SearchROI_SrcImg = cv::Rect(0, 0, 0, 0); + param_Local_SrcImg = cv::Point(0, 0); + det_Local_SrcImg = cv::Point(0, 0); + } + }; + // 边缘搜索定位结果 + struct Edge_AI_Result + { + int nresult; + cv::Rect roi; + bool buseOfft; + int offt_x; + int offt_y; + cv::Mat H; + + std::vector markresulList; + + Edge_AI_Result() + { + Init(); + } + void Init() + { + buseOfft = false; + nresult = 0; + offt_x = 0; + offt_y = 0; + roi = cv::Rect(0, 0, 0, 0); + markresulList.clear(); + if (!H.empty()) + { + H.release(); + /* code */ + } + } + }; + + enum SaveProcessType + { + Save_Close, // 不保存 + Save_Filter, // 过滤的 + Save_ALL, // 全部 + }; + + /// @brief 检测过程的参数 + struct DetConfig + { + int ncamId; // 相机ID + BaseCheckFunction *pBaseCheckFunction; + std::string strChannel; // 通道 + int nthresholdvalue; // 背景阈值 + int nAIErodesize; // 边缘腐蚀强度 + bool bSaveResultImg; // 保存结果图片 + SaveProcessType saveProcessImg; // 保存过程图片 + bool bUseDrawRoi_Check; // 是否用绘制的ROI进行校验 + cv::Rect drawRoi; // 绘制的 ROi; + cv::Mat drawMask; // 绘制的maksk + DetConfig() + { + Init(); + } + void Init() + { + pBaseCheckFunction = NULL; + ncamId = 0; + nthresholdvalue = 1; + nAIErodesize = 7; + bSaveResultImg = false; + saveProcessImg = Save_Close; + bUseDrawRoi_Check = false; + drawRoi = cv::Rect(0, 0, 0, 0); + if (!drawMask.empty()) + { + drawMask.release(); + /* code */ + } + } + void Print() + { + printf("nthresholdvalue:%d;nAIErodesize %d;bSaveResultImg %s SaveProcessImg %d\n", + nthresholdvalue, nAIErodesize, BOOL_TO_STR(bSaveResultImg), saveProcessImg); + + printf("bUseDrawRoi_Check %s roi %s \n", + BOOL_TO_STR(bUseDrawRoi_Check), CheckUtil::GetRectString(drawRoi).c_str()); + } + bool IsSaveProcessImg() + { + if (saveProcessImg != Save_Close) + { + return true; + } + + return false; + } + }; + +public: + AI_Edge_Algin(std::shared_ptr& log_ref); + ~AI_Edge_Algin(); + // 初始化检测模型 + int Init(OtherDet_Config *pOtherDet_Config); + int InitModel_ALL(); + int Detect(const cv::Mat &img, DetConfig *pDetConfig, std::shared_ptr &pCheckResult_Aling); + int SaveSmallImg(const cv::Mat &img, const cv::Mat &mask, cv::Rect roi); + // 利用mark 实现精确定位 + int MarkAlign(const cv::Mat &img, DetConfig *pDetConfig, cv::Rect bigroi); + +private: + int InitModel_Big(); + int InitModel_Mark(); + int Det_big(const cv::Mat &img, DetConfig *pDetConfig, std::string strChannel, cv::Rect &bigRoi); + int Det_MarkPoint(const cv::Mat &img, DetConfig *pDetConfig, cv::Rect bigroi, cv::Point SampleImg_Local); + int AnalsysMarkPoint(const cv::Mat &img, DetConfig *pDetConfig); + + int creatsavedir(); + +private: + bool m_bInitSucc; // 是否初始化成功 + // 检测结果 + std::shared_ptr m_pCheckResult_Aling; + + OtherDet_Config *m_pOtherDet_Config; + DetConfig *m_pDetConfig; + + std::shared_ptr& m_pdetlog; + + bool m_bInitialized; + bool m_bModelSucc; + bool m_bModel_Mark_Succ; + + bool m_bshowimg; + cv::Mat showimg; + std::string m_strRootPath_Big; + std::string m_strSavePath_Big; + std::string m_strRootPath_Mark; + std::string m_strSavePath_Mark; + std::string m_strLastDate; + + ImageStorage *m_pImageStorage; + + std::shared_ptr AI_Factory; + +private: + /* data */ +}; + +// 图片特征定位 +class Image_Feature_Algin +{ +public: + struct DetConfig + { + bool bSaveImg; + bool bSave_Process; // 存储过程图片 + + float fscore; + cv::Mat TemplateImg; // 模版图片 + cv::Mat DetImg; // 检测图片 + + cv::Rect Search_Roi; // 搜索 范围 + cv::Rect feature_Roi; // 特征区域 + cv::Rect param_CropRoi; // 裁剪区域,在参数图片上 + cv::Rect DetImg_CropROi; // 裁剪区域,在检测图片上 + DetConfig() + { + bSaveImg = false; + bSave_Process = false; + fscore = 0.9; + Search_Roi = cv::Rect(0, 0, 0, 0); + feature_Roi = cv::Rect(0, 0, 0, 0); + param_CropRoi = cv::Rect(0, 0, 0, 0); + DetImg_CropROi = cv::Rect(0, 0, 0, 0); + } + }; + +public: + Image_Feature_Algin(/* args */); + ~Image_Feature_Algin(); + int Detect(DetConfig *pDetConfig, Align_Result *pResult, std::vector &LogList); + +private: + cv::Point findBestTemplateMatch(const cv::Mat &detectionImage, const cv::Mat &templateImage, double &bestScore, int method = cv::TM_CCOEFF_NORMED); + +private: + PRINT_LOG_ m_PrintLog; + +private: + /* data */ +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/ALLImgCheckAnalysisy.hpp b/AlgorithmModule/include/ALLImgCheckAnalysisy.hpp new file mode 100644 index 0000000..5de6285 --- /dev/null +++ b/AlgorithmModule/include/ALLImgCheckAnalysisy.hpp @@ -0,0 +1,176 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:49:50 + * @LastEditTime: 2025-09-17 20:05:16 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/include/CamDeal.h + */ +#ifndef ALLImgCheckAnalysisy_H_ +#define ALLImgCheckAnalysisy_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "BlobBase.h" + +#include "ImgCheckBase.h" +#include "ImageDetBase.h" +#include "ImgCheckConfig.h" +#include "CheckErrorCodeDefine.hpp" +#include "ConfigBase.h" +#include "CheckConfigDefine.h" +#include "ImageDetConfig.h" +#include "Define_Product.hpp" +#include "CameraCheckAnalysisy.hpp" +#include "Product.h" + +using namespace std; +using namespace cv; + +class ALLImgCheckAnalysisy : public ALLImgCheckBase +{ + +public: + ALLImgCheckAnalysisy(); + ~ALLImgCheckAnalysisy(); + + // 初始化参数 pconfig 参数指针 返回:0 成功 其他异常 + int RunStart(void *pconfig1); + + // 设置检测数据,并开启检测 返回:0 成AT_THRESHOLD_TYPE_READY功 其他异常 + int SetDataRun_SharePtr(std::shared_ptr p); + + // 获取结果信息 返回:0 成功 其他异常 + int GetCheckReuslt(std::shared_ptr &pResult); + int ReJson(std::shared_ptr p, std::shared_ptr &pResult); + int CheckImg(std::shared_ptr p, std::shared_ptr &pResult); + + // 获取检测库 状态信息 返回:CHECK_THREAD_RUN_STATUS + int GetStatus(); + + // 更新参数 pconfig 参数指针,nConfigType 需要更新的参数类型 返回:0 成功 其他异常 + int UpdateConfig(void *pconfig, int nConfigType); + + std::string GetVersion(); + + std::string GetErrorInfo(); + +private: + // 加载运行参数 + int LoadRunConfig(void *p); + + // 加载分析参数 + int LoadCheckConfig(void *p); + + /// @brief 初始化并且启动程序 + /// @return + int InitRun(); + + /// @brief 开启检测 + /// @return + int StartCheck(); + + /// @brief 设置空闲 + /// @return + int SetIDLE(); + +private: + // 开启线程 + int StartThread(); + // 停止线程 + int StopThread(); + + // 退出系统 + int ExitSystem(); + + // 初始化相机检测分析类 + int InitCameraCheckAnalysisy(); + + // 初始化 + int InitData(); + + // 处理产品 + int Det_Product(std::shared_ptr &product); + std::shared_ptr GetProduct(); + + // 联合分析 + int AnalysiyAll(int productIdx); + + // 设置最终结果 + int SetProductResult(std::shared_ptr product); + // 设置检测完成 + int SetSetComplet_New(std::shared_ptr product, int nerror); + + + + // 加载图片 队列 + int PushInImg_New(std::shared_ptr p); + + + // 异常返回 + int ErrorReturn(std::shared_ptr p); + + + std::shared_ptr GetProduct(std::string strProduct); + + int InitAIFactory(); + +private: + // 图片处理线程 + std::shared_ptr ptr_thread_Run; + int Run(); // 运行; + int set_cpu_id(const std::vector &cpu_set_vec); + + +private: + RunInfoST m_RunConfig; + // 检测参数模块 + + + ConfigManagerBase *m_pConfigManager; + + // 图片处理线程 + + // 相机处理模块,负责完成对应相机图片的处理功能。 + std::unordered_map> m_pCameraCheckAnalysisyList; + + PRINT_LOG_ m_PrintLog; + // 互斥锁定义 +private: + + + // 产品队列 + std::vector> m_ProductList; + std::mutex mtx_ProductList; // 互斥量 + std::condition_variable ProductList_cond; // 条件变量, + + + std::shared_ptr m_pdetlog; + + + std::queue> m_CheckResultList; // 检测结果 + std::mutex mtx_CheckResult; // 互斥锁,用于保护数据队列 + std::condition_variable CheckResult_cond; // 条件变量,用于同步生产者和消费者线程 + + +private: + int m_nErrorCode; // 错误代码 + bool m_bInitSucc; // 初始化状态 + bool m_bExit; // 是否退出检测 + + std::string m_strTest; + + +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/BlobBase.h b/AlgorithmModule/include/BlobBase.h new file mode 100644 index 0000000..f9370ef --- /dev/null +++ b/AlgorithmModule/include/BlobBase.h @@ -0,0 +1,125 @@ +#pragma once + +enum ERR_DOT_TYPE_ENUM +{ + ERR_TYPE_1, + ERR_TYPE_2, + ERR_TYPE_COUNT, +}; +#define Value_ERR_TYPE_1 64 +#define Value_ERR_TYPE_2 128 + +//-----------------------sxg added +#define _MAX_ERROR_SCAN_LINE_PER_ROW 300 +#define _MAX_ERROR_DOT_BLOB 500 +#define _MAX_MACRO_COUNT 4 + +#define _MAX_ERR_CLASS ERR_TYPE_COUNT +// #define _CAM_WIDTH 640 +#define _MAX_MIN_VALUE_NUM 10 +typedef struct ERROR_DOTS_SCAN_DATA +{ + unsigned short x, count; + unsigned short minx, miny; + unsigned short maxx, maxy; + int area, energy; + int xposSum, yposSum; + int macro; + int type; + int ErrClass[_MAX_ERR_CLASS]; +} ERROR_DOTS_SCAN_DATA; + +typedef struct ERROR_DOTS_SCAN_ROW +{ + int scanCount; + ERROR_DOTS_SCAN_DATA errorScanLineTab[_MAX_ERROR_SCAN_LINE_PER_ROW]; + int macro[_MAX_MACRO_COUNT]; + int ErrClass[_MAX_ERR_CLASS]; + int minValue[_MAX_MIN_VALUE_NUM]; +} ERROR_DOTS_SCAN_ROW; + +typedef struct ERROR_DOTS_BLOB_DATA +{ + unsigned short x, y; + unsigned short minx, miny; + unsigned short maxx, maxy; + int area; + int energy; + float JudgArea; + float len; + float breadth; + int macro[_MAX_MACRO_COUNT]; + int ErrClass[_MAX_ERR_CLASS]; + int whiteOrblack; + int ErrType; + int UserErrorType; + int maxValue; + float grayDis; + int AIclasstype; + float density; + unsigned short badd; +} ERROR_DOTS_BLOB_DATA; + +typedef struct ERROR_DOTS_BLOBS +{ + int blobCount; + int srcBlobCount; + int totalArea; + int totalEnergy; + ERROR_DOTS_BLOB_DATA blobTab[_MAX_ERROR_DOT_BLOB]; + int ErrClass[_MAX_ERR_CLASS]; +} ERROR_DOTS_BLOBS; + +typedef struct ERROR_DOTS_BLOB_PARAM +{ + int minArea; // ²ÐµãÇøÓòÃæ»ý×îСֵ£¬µ¥Î»ÎªÏñËØµã£¬Èç¹ûСÓÚ´ËÖµ£¬ÔòºöÂÔ + int minEnergy; // ²ÐµãÇøÓòÄÜÁ¿×îСֵ£¬Èç¹ûСÓÚ´ËÖµ£¬ÔòºöÂÔ + + int maxErrorBlobCount; // ×î´óÔÊÐíµÄÂú×ãÉÏÊöÌõ¼þºóµÄ²ÐµãÇøÓòÊýÁ¿£¬Èç¹û´óÓÚ´ËÖµ£¬ Ôò±¨´í + int maxTotalArea; // ×î´óÔÊÐíµÄÂú×ãÉÏÊöÌõ¼þºóµÄ²ÐµãÇøÓò×ÜÃæ»ý£¬Èç¹û´óÓÚ´ËÖµ£¬ Ôò±¨´í + int maxTotalEnergy; // ×î´óÔÊÐíµÄÂú×ãÉÏÊöÌõ¼þºóµÄ²ÐµãÇøÓò×ÜÄÜÁ¿£¬Èç¹û´óÓÚ´ËÖµ£¬ Ôò±¨´í + + int maxRegionArea; // ×î´óÔÊÐíµÄµ¥¸ö²ÐµãÇøÓòÃæ»ý£¬Èç¹û´óÓÚ´ËÖµ£¬ Ôò±¨´í + int maxRegionEnergy; // ×î´óÔÊÐíµÄµ¥¸ö²ÐµãÇøÓòÄÜÁ¿£¬Èç¹û´óÓÚ´ËÖµ£¬ Ôò±¨´í + int Hthold[4]; // ѧϰģ°æºóµÄÀ©Õ¹ãÐÖµ + int Lthold[4]; // ѧϰģ°æºóµÄÀ©Õ¹ãÐÖµ + int Level[2]; // ÑÏÖØµÈ¼¶ + int mergeDistance; // ²ÐµãºÏ²¢×îС¾àÀë £¬¡¡ÈôÁ½¸ö²Ðµã¾àÀëСÓÚ´ËÖµÔòºÏ²¢ÎªÒ»¸ö + int isUseMacro; +} ERROR_DOTS_BLOB_PARAM; + +typedef struct ERROR_BLOBS_PARAM +{ + int id; + unsigned char *pb; + unsigned char *pr; + unsigned char *pc; + int width; + int height; + int obj; + ERROR_DOTS_BLOBS *blobs; + +} ERROR_BLOBS_PARAM; +#ifdef __cplusplus +extern "C" +{ +#endif + void pretest(double x); + extern void AddErrorScan(ERROR_DOTS_SCAN_ROW *curRow, ERROR_DOTS_SCAN_ROW *prevRow, int x, int len, int y, int difSum, int minArea, int minEng, int mdx, int *pErrClass); + extern void LinkScanLineToBlob(ERROR_DOTS_BLOBS *blobs, ERROR_DOTS_SCAN_ROW *prevRow, int sx, int sy, int minArea, int minEnergy, int mergeDistanceX, int mergeDistanceY, int width); + extern void SortBlob(ERROR_DOTS_BLOBS *blobs); + extern void MergeBlob(ERROR_DOTS_BLOBS *blobs, ERROR_DOTS_BLOB_PARAM *param); + extern void AddErrorScan_New(ERROR_DOTS_SCAN_ROW *curRow, ERROR_DOTS_SCAN_ROW *prevRow, int x, int len, int y, int difSum, int minArea, int minEng, int errorType); + extern void LinkScanLineToBlob_New(ERROR_DOTS_BLOBS *blobs, ERROR_DOTS_SCAN_ROW *prevRow, int sx, int sy, int minArea, int minEnergy, int mergeDistanceX, int mergeDistanceY, int width); + + extern int GetBlobs_V2(ERROR_DOTS_BLOBS *blobs, unsigned char *pImgdata, unsigned char *pErrordata, int width, int height, int basev, int minArea); + extern int GetBlobs_V3(ERROR_DOTS_BLOBS *blobs, unsigned char *pErrordata, int width, int height, int minArea); + extern int GetBlobs_V3_CA(ERROR_DOTS_BLOBS *blobs, unsigned char *pErrordata, int width, int height, int minArea, int err_1_value, int err_2_value); + extern int GetBlobs_ALL_New(ERROR_DOTS_BLOBS *blobs, unsigned char *pErrordata, unsigned char *pHdata, int width, int height, int minArea); + extern int GetBlobs_oneLabe(ERROR_DOTS_BLOBS *blobs, unsigned char *pErrordata, unsigned char *pHdata, int width, int height, int minArea); + + extern int PushBlob(ERROR_DOTS_BLOBS *blobs, ERROR_DOTS_BLOBS *addblobs); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/CameraCheckAnalysisy.hpp b/AlgorithmModule/include/CameraCheckAnalysisy.hpp new file mode 100644 index 0000000..5321767 --- /dev/null +++ b/AlgorithmModule/include/CameraCheckAnalysisy.hpp @@ -0,0 +1,240 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:49:50 + * @LastEditTime: 2025-09-17 20:10:01 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/include/CamDeal.h + */ +#ifndef CameraCheckAnalysisy_H_ +#define CameraCheckAnalysisy_H_ + +#include +#include +#include +#include +#include +#include +#include "Define_Base.h" +#include "ImgCheckBase.h" +#include "ImageDetBase.h" +#include "ImgCheckConfig.h" +#include "CheckErrorCodeDefine.hpp" +#include "ConfigBase.h" +#include "CheckConfigDefine.h" +#include "ImageDetConfig.h" +#include "Define_Product.hpp" +#include "CameraResult.h" +#include "DetLog.h" +#include "ImageResultJudge.h" +#include "CheckResultJson.h" + +using namespace std; +using namespace cv; +// 相机处理类 +class CameraCheckAnalysisy +{ +public: + // 搜索方向 + enum Edge_DirectSign + { + DirectSign_UP, + DirectSign_DOWN, + DirectSign_Left, + DirectSign_Right, + }; + // 搜索边缘了下,黑还是白 + enum Search_Value_Type + { + Search_Value_White, + Search_Value_Black, + }; + // 边缘搜索参数 + struct Edge_Search_Config + { + cv::Rect roi; // 边缘搜索区域 + Search_Value_Type searchValueType; // 搜索边缘了下,黑还是白 + Edge_DirectSign directSign; // 搜索方向 + int nValueThreshold; // 灰度阈值 + int nSearchCount; // 搜索点的个数 把roi 均分成多少个点。 + int nSearchrange; // 搜索范围,一般为单数,如果 1表示 搜索当前点,如果3表示 除了当前点,还有左右 点。5表示 从-2到2 + int stepCount; // 每个搜索点的步数 + int nLimit; // 连续搜索多个满足阈值的点后,停止搜索,当前搜索点 搜索成功。 + std::string strchannel; + Edge_Search_Config() + { + roi = cv::Rect(0, 0, 0, 0); + directSign = DirectSign_UP; + searchValueType = Search_Value_White; + nValueThreshold = 40; + nSearchCount = 30; + nSearchrange = 1; + stepCount = 2; + nLimit = 3; + strchannel = ""; + } + bool CheckConfigValid() + { + bool bRet = true; + if (roi.width <= 0 || roi.height <= 0) + { + printf("s1 \n"); + return false; + } + if (searchValueType < Search_Value_White || searchValueType > Search_Value_Black) + { + printf("s2 \n"); + return false; + } + if (directSign < 0 || directSign > 4) + { + printf("s3 \n"); + return false; + } + if (nValueThreshold < 0 || nValueThreshold > 255) + { + printf("s4 \n"); + return false; + } + if (nSearchCount < 0) + { + printf("s5 \n"); + return false; + } + if (stepCount < 0) + { + printf("s6 \n"); + return false; + } + if (nLimit < 0) + { + printf("s7 \n"); + return false; + } + return true; + } + }; + struct Line + { + cv::Point p1; + cv::Point p2; + Line() + { + p1 = cv::Point(0, 0); + p2 = cv::Point(0, 0); + } + }; + +public: + CameraCheckAnalysisy(); + ~CameraCheckAnalysisy(); + + // 相机处理类 初始化 + int Init(std::string strcameraName); + int StartCheck(std::shared_ptr pCamera_Check_Result); + +private: + // 开启线程 + int StartThread(); + // 停止线程 + int StopThread(); + + // 初始化检测分析线程类 + int InitCheckAnalysisy(); + // 初始化其他 + int InitRun(); + // 设置新的检测参数 + int SetNewConfig(); + // 处理每张图片 + int CheckImgRun(); + + int Run(); // 运行; + int set_cpu_id(const std::vector &cpu_set_vec); + // 等待处理图片 + int WaitDetImg(); + + // 预处理图片 + int Detect_Pre(); + + // 合并图片 + int Mergimg(cv::Mat &img, const cv::Mat &img_B, std::string strcam, std::string strchannel); + + int GetRectAndPoint(const cv::Mat &img,cv::Rect& roi,cv::Point& merg_p_up, cv::Point& merg_p_down,bool bleft , std::string strcam, std::string strchannel); + + // 检测图片 + + // 处理每张图片 + int Detect_Images(); + + // 结果参数分析 + int ResultParamJudge(); + + // 边缘处理 + int ImgEdge(cv::Mat img, cv::Mat &detMaskImg, cv::Rect &roi, int productIdx); + + // 插入相机日志 + int InsertCameraLog(); + + ChannelCheckFunction *GetChannelFuntion(std::string strChannelName); // 获得 通道的检测功能 + + // 预处理 字符检测 + int preDet_ZF(std::shared_ptr p, std::shared_ptr &pResult); + + // 获取 检测核心库 + ImgCheckBase *GetDealResult(int idx = -1); + + // 边缘点搜索函数 + int GetEdgePoint(const cv::Mat &img, Edge_Search_Config *pEdge_Search_Config, int &outP); + + int GetLine(const cv::Mat &img, std::vector &pointList, int lineNum, int xory, int &outP); + +public: + // 运行的基本参数 + RunInfoST m_RunConfig; + + // 检测参数模块 + std::shared_ptr m_pConfig; + int m_nConfigIdx; + + // 检测分析参数 + AnalysisyConfigST m_AnalysisyConfig; + CommonConfigNodeST *m_pCommonAnalysisyConfig; + ALLChannelCheckFunction *m_pChannelFuntion; // 画面检测功能 + BaseCheckFunction *m_pbaseCheckFunction; // 基础检测 + + std::shared_ptr m_pdetlog; + + // 结果分析类 + ImageResultJudge m_imageResultJudge; + +private: + // 相机ID + std::string m_strcameraName; + + int m_nErrorCode; // 错误代码 + bool m_bInitSucc; // 初始化状态 + bool m_bExit; // 是否退出检测 + int nLastCheckAnalysisyThreadIdx; + // 图片处理线程 + std::shared_ptr ptr_thread_Run; + + std::shared_ptr m_pCheck_Result; + + bool m_bHaveImgeDet; // 是否有图片需要检查 + std::mutex mtx_WaiteImg; // 等待图片的锁 + std::condition_variable cond_WaiteImg; // 条件变量,是否有图片需要检查 + +private: + // 检测核心库 + ImgCheckBase *m_pImgCheckAnalysisy[IMGCHECKANALYSISY_NUM]; + + CheckResultJson m_CheckResultJson; + +private: + cv::Mat showimg; + bool bshowimg; + +private: +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/CameraResult.h b/AlgorithmModule/include/CameraResult.h new file mode 100644 index 0000000..5ab8038 --- /dev/null +++ b/AlgorithmModule/include/CameraResult.h @@ -0,0 +1,74 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:49:50 + * @LastEditTime: 2025-09-16 21:20:28 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/include/CamDeal.h + */ +#ifndef CameraResult_H_ +#define CameraResult_H_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Define_Product.hpp" +#include "CheckErrorCodeDefine.hpp" +#include "ImgCheckConfig.h" +#include "ImageDetConfig.h" +#include "ImageAllResult.h" +#include "DetLog.h" +using namespace std; +using namespace cv; +class CameraResult +{ +private: + /* data */ +public: + CameraResult(/* args */); + ~CameraResult(); + + void AddLog(std::string str); + + // 添加图片信息 + int AddDetImage(std::shared_ptr p); + // 是否全部检测完成 + bool bCheckCamplate(); + + // 设置 检测步骤 + Check_Step GetCheckStep(); + void SetCheckStep(Check_Step step); + + // 送图是否全部完成 + bool getImgPushComplate(); + void setImgPushComplate(); + + // 返回一个未检测的 图片进行检测 + std::shared_ptr GetNoDetImg(); + long time_start; + bool bJson = false; + +public: + std::vector LogList; + std::shared_ptr detlog; + std::vector> ImageALLDetResultList; // 每个通道的检测结果 ,返回的结果。 + std::shared_ptr productBaseResult; + std::shared_ptr cameraBaseResult; + CameraImage_Status cameraImage_Status; // 图片状态 + + std::mutex mtx_Det; // 互斥量 +private: + bool bIsImgComplete = false; // 图片是否都送完了。 + Check_Step checkStep = Check_Step_NODet; // 检测步骤 + PRINT_LOG_ m_PrintLog; + // 多线程安全 + std::mutex mtx_DetImageList; +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/CheckErrorCodeDefine.hpp b/AlgorithmModule/include/CheckErrorCodeDefine.hpp new file mode 100644 index 0000000..e94e96d --- /dev/null +++ b/AlgorithmModule/include/CheckErrorCodeDefine.hpp @@ -0,0 +1,285 @@ + + +#ifndef _CheckErrorDefine_HPP_ +#define _CheckErrorDefine_HPP_ +#include +#include +#include "CheckUtil.hpp" +#include "Base_Define.h" +#include "Define_Base.h" +#include "Define_Error.h" +#include "DetLog.h" +#define BOOL_TO_STR(bool_expr) (bool_expr) ? "true" : "false" +#define BOOL_TO_STROK(bool_expr) (bool_expr) ? "OK" : "NG" +#define BOOL_TO_ThanLess(bool_expr) (bool_expr) ? ">" : "<" +#define BOOL_TO_LessThan(bool_expr) (bool_expr) ? "<" : ">" +#define BOOL_TO_STR_Error(bool_expr) ((bool_expr) ? "Succ" : "Error") +#define Re_TO_STR_Error(num) ((num) == 0 ? "Succ" : "Error") +#define Re_TO_STR_False(num) ((num) == 0 ? "Succ" : "false") +#define Re_TO_STR_Pass_1(num) ((num) == 1 ? "Pass" : "fail") +#define Re_TO_STR_NG(num) ((num) == 0 ? "OK" : "NG") +#define SRC_IMG_WIDTH 14192 +#define SRC_IMG_HEIGHT 10640 + +// 输入模型图片尺寸 +#define SRC_AI_In_IMAGE_WIDTH 800 +#define SRC_AI_In_IMAGE_HEIGHT 800 + +// resize 图片的 宽度 +#define RESIZE_IMAGE_WIDTH 1680 + + +enum TEM_IMG_IDX_ +{ + TEM_IMG_IDX_SrcCrop, + TEM_IMG_IDX_AImask, + TEM_IMG_IDX_DrawSrc, + TEM_IMG_IDX_Result, + TEM_IMG_IDX_Count, +}; +static const std::string TEM_IMG_IDX_Names[] = + { + "SrcCrop", + "AImask", + "Drawmask", + "result"}; + +enum Print_Level_ +{ + Print_Level_Info, + Print_Level_Key, + Print_Level_Error, +}; +// 大于日志 +struct PRINT_LOG_ +{ + bool bprint; + bool bshow_Info; + bool bshow_Key; + bool bshow_Error; + + PRINT_LOG_() + { + Init(); + } + void Init() + { + bprint = true; + bshow_Info = true; + bshow_Key = true; + bshow_Error = true; + } + + template + std::string printstr(int LogLevel, std::string stepStr, const std::string &format, Args... args) + { + std::string str = ""; + if (!bprint) + { + return str; + } + switch (LogLevel) + { + case Print_Level_Info: + if (!bshow_Info) + { + return str; + } + str = "info-> "; + break; + case Print_Level_Key: + if (!bshow_Key) + { + return str; + } + str = "key-> "; + break; + case Print_Level_Error: + if (!bshow_Error) + { + return str; + } + str = "Error-> "; + break; + default: + return str; + break; + } + + str += stepStr + ": "; + str += str_Format(format, args...); + printf("%s\n", str.c_str()); + + return str; + } +}; + + + +// 检测区域参数 +struct Detect_ROI_Config +{ + bool bdraw; // 是否绘制 + std::vector> roiList_Src; + std::vector> roiList_Show; + Detect_ROI_Config() + { + Init(); + } + void Init() + { + bdraw = false; + for (auto &innerVec : roiList_Src) + { + innerVec.clear(); + } + roiList_Src.clear(); // 清空外层vector + + for (auto &innerVec : roiList_Show) + { + innerVec.clear(); + } + roiList_Show.clear(); // 清空外层vector + } + void Update(const std::vector &list, const cv::Rect &roi, float fScale_x, float fScale_y) + { + + std::vector adjustedPolygon; + std::vector adjustedPolygon_size; + // 遍历多边形中的每个点,并根据roi调整位置 + for (const auto &point : list) + { + // 调整每个点的位置,平移到roi的位置 + cv::Point adjustedPoint(point.x - roi.x, point.y - roi.y); + // printf("-- %d %d \n", adjustedPoint.x, adjustedPoint.y); + if (adjustedPoint.y < 0) + { + adjustedPoint.y = 0; + } + + cv::Point sizep; + sizep.x = adjustedPoint.x * fScale_x; + sizep.y = adjustedPoint.y * fScale_y; + adjustedPolygon.push_back(adjustedPoint); + adjustedPolygon_size.push_back(sizep); + } + + // 将调整后的多边形添加到roiList_Src + roiList_Src.push_back(adjustedPolygon); + roiList_Show.push_back(adjustedPolygon_size); + } + void Update_1(const std::vector &list, const cv::Rect &roi, int offtx, int offty, float fScale_x, float fScale_y) + { + + std::vector adjustedPolygon; + std::vector adjustedPolygon_size; + // 遍历多边形中的每个点,并根据roi调整位置 + for (const auto &point : list) + { + // 调整每个点的位置,平移到roi的位置 + cv::Point adjustedPoint(point.x + offtx - roi.x, point.y + offty - roi.y); + if (adjustedPoint.y < 0) + { + adjustedPoint.y = 0; + } + + cv::Point sizep; + sizep.x = adjustedPoint.x * fScale_x; + sizep.y = adjustedPoint.y * fScale_y; + adjustedPolygon.push_back(adjustedPoint); + adjustedPolygon_size.push_back(sizep); + } + + // 将调整后的多边形添加到roiList_Src + roiList_Src.push_back(adjustedPolygon); + roiList_Show.push_back(adjustedPolygon_size); + } + void Update_Marit(const std::vector &list, const cv::Rect &roi, cv::Mat &H, float fScale_x, float fScale_y) + { + + std::vector adjustedPolygon; + std::vector adjustedPolygon_size; + // 遍历多边形中的每个点,并根据roi调整位置 + for (const auto &point : list) + { + + cv::Point pt = CheckUtil::transformPoint(point, H); + // printf(" %d %d -> %d %d \n",point.x,point.y,pt.x,pt.y); + // 调整每个点的位置,平移到roi的位置 + cv::Point adjustedPoint(pt.x - roi.x, pt.y - roi.y); + if (adjustedPoint.y < 0) + { + adjustedPoint.y = 0; + } + + cv::Point sizep; + sizep.x = adjustedPoint.x * fScale_x; + sizep.y = adjustedPoint.y * fScale_y; + adjustedPolygon.push_back(adjustedPoint); + adjustedPolygon_size.push_back(sizep); + } + + // 将调整后的多边形添加到roiList_Src + roiList_Src.push_back(adjustedPolygon); + roiList_Show.push_back(adjustedPolygon_size); + } + // 判断点是否在指定idx的ROI内 + bool isPointInROI(int idx, const cv::Point &point) + { + // 判断索引是否有效 + if (idx < 0 || idx >= roiList_Src.size()) + { + printf("Invalid idx: %d\n", idx); + return false; + } + + // 获取第 idx 个多边形 + const std::vector &polygon = roiList_Src[idx]; + + // 使用 pointPolygonTest 来判断点是否在多边形内 + double result = cv::pointPolygonTest(polygon, point, false); + + // 如果结果大于 0,则点在多边形内 + if (result > 0) + { + return true; + } + // 如果结果等于 0,点在边界上 + else if (result == 0) + { + return true; // 你可以根据需求调整边界情况 + } + + // 如果结果小于 0,点在多边形外 + return false; + } + + void print(std::string str) + { + printf("%s bdraw %d roi num %ld\n", str.c_str(), bdraw, roiList_Src.size()); + } +}; +// 复测的状态 +enum ReJson_Status +{ + ReJson_Status_Idel, + ReJson_Status_start, + ReJson_Status_Run, + ReJson_Status_end, +}; +struct AD_Channel_Info_ +{ + cv::Rect roi; + int num; + float fdis; + AD_Channel_Info_() + { + roi = cv::Rect(0, 0, 0, 0); + num = 0; + fdis = 999999999999; + } +}; + +extern std::string GetErrorCodeInfo(int nErrorCode); + +#endif //_CORELOGICFACTORY_HPP_ \ No newline at end of file diff --git a/AlgorithmModule/include/CheckResultJson.h b/AlgorithmModule/include/CheckResultJson.h new file mode 100644 index 0000000..144f435 --- /dev/null +++ b/AlgorithmModule/include/CheckResultJson.h @@ -0,0 +1,28 @@ +/* +//其他类的检测 + */ +#ifndef CheckResultJson_H_ +#define CheckResultJson_H_ +#include +#include +#include "ImgCheckConfig.h" +#include "JsonCoversion.h" +#include +#include "ImageDetConfig.h" +class CheckResultJson : public JsonCoversion +{ +public: + CheckResultJson() {} + virtual ~CheckResultJson() {} + +public: + virtual Json::Value toJsonValue(); + virtual void toObjectFromValue(Json::Value root); + int GetConfig(std::string strJson, std::shared_ptr &pOneImgDetResult); + std::string GetResultString(std::shared_ptr &pOneImgDetResult); + +private: + std::shared_ptr m_pOneImgDetResult; +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/CheckUtil.hpp b/AlgorithmModule/include/CheckUtil.hpp new file mode 100644 index 0000000..51e9f2e --- /dev/null +++ b/AlgorithmModule/include/CheckUtil.hpp @@ -0,0 +1,80 @@ +/* + * @Descripttion: + * @version: + * @Author: sueRimn + * @Date: 2022-04-28 10:41:42 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-08-03 21:32:02 + */ +/* + * FileName:CoreLogicFactory.hpp + * Version:V1.0 + * Description: + * Created On:Mon Sep 10 11:13:13 UTC 2018 + * Modified date: + * Author:Sky + */ +#ifndef _CheckUtil_HPP_ +#define _CheckUtil_HPP_ +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; +class CheckUtil +{ +public: + static long getcurTime(); + static std::string getCurrentDate(); + static std::string getCurTimeHMS(); + static std::string Op_float2String(float nvalue); + static int64_t getSnowId(); + static bool JudgRect(cv::Rect roi, int img_w, int img_h); + static bool JudgRect_SZ(cv::Rect roi, int w, int h); + static bool compareIgnoreCase(const std::string &str1, const std::string &str2); + static bool RoiInImg(cv::Rect roi, cv::Mat img); + static int printROI(cv::Rect roi, std::string str = ""); + static float CalIoU(cv::Rect rect1, cv::Rect rect2); + static float CalIoU_t(cv::Rect rect1, cv::Rect rect2); + static int CheckRect(cv::Rect &roi, int img_w, int img_h); + static int SizeRect(cv::Rect &roi, int img_w, int img_h, int addw, int addh); + static int CalHj(const cv::Mat &img, const cv::Mat &mask,int b_value); + static int CalHj(const cv::Mat &img, const cv::Mat &mask,const cv::Mat &backgroundimg); + static int CalHjWeighted(const cv::Mat &img, const cv::Mat &mask, int b_value, float power = 2.0f); + // 计算平均灰度 + static float CalImgBrightness(cv::Mat imgRoi); + // 计算角度 + static float Cal2PointAngle(cv::Point p_left, cv::Point p_right); + + // 找图片的最大外轮廓 + static cv::Rect getLargestContourROI(const cv::Mat &binaryImg, bool &found); + + static std::string GetRectString(cv::Rect rect); + //创建目录 + static int CreateDir(const std::string &dir); + + // 点的距离是否过小 + static bool bcalDis(cv::Point p1, cv::Point p2, int disT); + static double calDis(cv::Point p1, cv::Point p2); + static void PrintRect(cv::Rect roi, std::string str = ""); + static int cutSmallImg(cv::Mat img, std::vector &samllRoiList, cv::Rect config_roi, int config_SmallImg_Width, int config_SmallImg_Height, int config_MinOverlap_Width, int config_MinOverlap_Height); + static cv::Point2f transformPoint(const cv::Point2f &point, const cv::Mat &transform_matrix); +}; +template +static std::string str_Format(const std::string &format, Args... args) +{ + auto size_buf = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; + std::unique_ptr buf(new (std::nothrow) char[size_buf]); + + if (!buf) + return std::string(""); + + std::snprintf(buf.get(), size_buf, format.c_str(), args...); + return std::string(buf.get(), buf.get() + size_buf - 1); + +} +#endif //_CORELOGICFACTORY_HPP_ \ No newline at end of file diff --git a/AlgorithmModule/include/Define_Base.h b/AlgorithmModule/include/Define_Base.h new file mode 100644 index 0000000..4531050 --- /dev/null +++ b/AlgorithmModule/include/Define_Base.h @@ -0,0 +1,43 @@ +/* +//定义整个系统基础的 定义 信息 + */ +#ifndef Define_Base_H_ +#define Define_Base_H_ +#include +#include +#include "CheckUtil.hpp" +#include "ImgCheckConfig.h" +#include "ImageDetConfig.h" +#include "Define_Error.h" + +// 检测分析线程类数目 +#define IMGCHECKANALYSISY_NUM 2 + + + +// 相机ID 的相关定义 +enum Camera_IDX +{ + Camera_IDX_0 = 0, + Camera_IDX_1 = 1, +}; +static const std::string strCameraName[] = + { + "left", + "right"}; +struct Camera_Info +{ + Camera_IDX camera_ID; + std::string camera_name; + Camera_Info() + { + Init(); + } + void Init() + { + camera_ID = Camera_IDX_0; + camera_name = strCameraName[camera_ID]; + } +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/Define_Error.h b/AlgorithmModule/include/Define_Error.h new file mode 100644 index 0000000..a4e7586 --- /dev/null +++ b/AlgorithmModule/include/Define_Error.h @@ -0,0 +1,67 @@ +/* +//定义整个系统基础的 定义 信息 + */ +#ifndef Define_Error_H_ +#define Define_Error_H_ +#include +using namespace std; + +enum ERRORCODEDEFINE +{ + CHECK_OK, + CHECK_ERROR_VERSION, // 参数或接口版本问题 + CHECK_ERROR_Config_Null, // 参数指针为空 + CHECK_ERROR_Config_Value, // 参数值错误 + CHECK_ERROR_Path_NULL, // 路径为空 + CHECK_ERROR_Mask_Empty, // mask 图片为空 + CHECK_ERROR_Config_cutRoi, // 参数的 roi 错误 + CHECK_ERROR_CheckImg_Empty, // 检测 图片为空 + CHECK_ERROR_PushImg_ListSize, // 送图错误 队列太长 + CHECK_ERROR_PushImg_NoDetChannel, // 不检测通道 + CHECK_ERROR_PushImg_Existing_ID, // ID 已存在 + CHECK_ERROR_PushImg_ID_Error, // ID 错误 + CHECK_ERROR_ID_Error, // ID 错误 + CHECK_ERROR_L255_Empty, // L255 为空 + CHECK_ERROR_L255_Edge_Fail, // L255 边界搜索失败 + CHECK_ERROR_PRODUCT_ID_EXIST, // 产品 ID 已存在 + CHECK_ERROR_Camear_ID_Error, // 相机ID 错误 + INIT_CameraCheck_Error, // 初始化 相机处理类错误 +}; +static const std::string str_ErrorName[] = + { + "ok", + "ERROR_VERSION", + "Config_Null", + "Config_Value", + "Path_NULL", + "Mask_Empty", + "Config_cutRoi", + "CheckImg_Empty", + "PushImg_ListSize", + "PushImg_NoDetChannel", + "PushImg_Existing_ID", + "PushImg_ID_Error", + "ID_Error", + "L255_Empty", + "L255_Edge_Fail", + "L255_Empty", + "L255_Empty", + "PRODUCT_ID_EXIST", + "Camear_ID_Error", + "INIT_CameraCheck_Error"}; +struct ErrorInfo +{ + int nerror_code; // 错误代码 + string strerror_msg; // 错误信息 + ErrorInfo() + { + Init(); + } + void Init() + { + nerror_code = CHECK_OK; + strerror_msg = str_ErrorName[CHECK_OK]; + } +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/Define_Product.hpp b/AlgorithmModule/include/Define_Product.hpp new file mode 100644 index 0000000..02b93de --- /dev/null +++ b/AlgorithmModule/include/Define_Product.hpp @@ -0,0 +1,43 @@ + + +#ifndef Define_Product_HPP_ +#define Define_Product_HPP_ +#include "Define_Base.h" +#include "ImgCheckConfig.h" + +// 相机的一些状态情况 +struct CameraImage_Status +{ + bool bImgComplete; /// 图片送完成了 + bool bHaveImg; // 是否有图片 + bool bHave_L255; // 是否有L55图片 + bool bHave_DP; // 是否有DP图片 + bool bhave_UP; // 是否有UP图片 + bool bDetCutRoi; // 是否完成边缘检测 + CameraImage_Status() + { + Init(); + } + void Init() + { + bImgComplete = false; + bHaveImg = false; + bHave_L255 = false; + bHave_DP = false; + bhave_UP = false; + bDetCutRoi = false; + } +}; +// 处理状态 +enum Check_Step +{ + Check_Step_NODet = 0, // 未处理 + Check_Step_PreDet, // 预处理 + Check_Step_ImgeDet, // 图片处理 + Check_Step_ResultParamJudg, // 结果参数判断 + Check_Step_ImgeDet_End, // 图片检测完成 + Check_Step_Complete, // 处理完成 + Check_Step_COUNT, +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/DetLog.h b/AlgorithmModule/include/DetLog.h new file mode 100644 index 0000000..b8f53c1 --- /dev/null +++ b/AlgorithmModule/include/DetLog.h @@ -0,0 +1,151 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:49:50 + * @LastEditTime: 2025-09-16 22:35:59 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/include/CamDeal.h + */ +#ifndef DetLog_H_ +#define DetLog_H_ +#include +#include +#include +#include +#include +#include +#include "ImgCheckConfig.h" +#include "CheckErrorCodeDefine.hpp" +using namespace std; +enum PrintLevel_ +{ + PrintLevel_0, + PrintLevel_1, + PrintLevel_2, + PrintLevel_3, + PrintLevel_4, +}; +template +std::string str_Format_1(const std::string &format, Args... args) +{ + // 先尝试用小缓冲 + char buf[256]; + int size = std::snprintf(buf, sizeof(buf), format.c_str(), args...); + + if (size < 0) + return {}; + + if (size < sizeof(buf)) + { + return std::string(buf, size); // 直接返回 + } + else + { + // 超过栈缓存时才用堆分配 + std::vector dynamic_buf(size + 1); + std::snprintf(dynamic_buf.data(), dynamic_buf.size(), format.c_str(), args...); + return std::string(dynamic_buf.data(), size); + } +} + +// 检测过程临结果 +struct DetLog +{ + + std::vector logList; + bool bPrintStr; // 是否打印日志 + int addLogLevel; + + DetLog() + { + Init(); + } + void Init() + { + logList.clear(); + bPrintStr = false; + addLogLevel = DET_LOG_LEVEL_3; + } + + template + void AddCheckstr(PrintLevel_ step, std::string stepStr, const std::string &format, Args... args) + { + std::string str = ""; + + if (step <= PrintLevel_0) + { + str += ".. "; + } + else if (step == PrintLevel_1) + { + str += "..... "; + } + else if (step == PrintLevel_2) + { + str += "........ "; + } + else if (step == PrintLevel_3) + { + str += "........... "; + } + else if (step >= PrintLevel_4) + { + str += ".............. "; + } + str += stepStr + ": "; + str += str_Format_1(format, args...); + if (bPrintStr) + { + printf("%s\n", str.c_str()); + } + + logList.push_back(str); + } + template + void AddCheckstr(PrintLevel_ step, int LogLevel, std::string stepStr, const std::string &format, Args... args) + { + std::string str = ""; + + if (step <= PrintLevel_0) + { + str += ".. "; + } + else if (step == PrintLevel_1) + { + str += "..... "; + } + else if (step == PrintLevel_2) + { + str += "........ "; + } + else if (step == PrintLevel_3) + { + str += "........... "; + } + else if (step >= PrintLevel_4) + { + str += ".............. "; + } + str += stepStr + ": "; + str += str_Format_1(format, args...); + if (bPrintStr) + { + printf("%s\n", str.c_str()); + } + + if (LogLevel <= addLogLevel) + { + logList.push_back(str); + } + } + void printLog(std::string str) + { + printf("===========================%s==============================\n", str.c_str()); + for (auto strl : logList) + { + printf("%s\n", strl.c_str()); + } + printf("==========================================================\n"); + } +}; +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/Edge_QX_Det.h b/AlgorithmModule/include/Edge_QX_Det.h new file mode 100644 index 0000000..907f04e --- /dev/null +++ b/AlgorithmModule/include/Edge_QX_Det.h @@ -0,0 +1,252 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-08-04 21:26:32 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-08-13 16:05:08 + * @FilePath: /BOE_CELL_AOI/AlgorithmModule/include/Edge_QX_Det.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-08-04 21:26:32 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-08-04 21:29:05 + * @FilePath: /BOE_CELL_AOI/AlgorithmModule/include/Edge_QX_Det.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/* +//实现对部分缺陷 需要进行 数量 和距离上分析的 + */ +#ifndef Edge_QX_Det_H_ +#define Edge_QX_Det_H_ +#include + +#include "CheckErrorCodeDefine.hpp" +#include "ImageDetConfig.h" +#include "CheckConfigDefine.h" + +using namespace std; +using namespace cv; + +// 边缘缺陷检测 +class Edge_QX_Det +{ +public: + // 搜索方向 + enum Edge_DirectSign + { + DirectSign_UP, + DirectSign_DOWN, + DirectSign_Left, + DirectSign_Right, + }; + // 搜索边缘了下,黑还是白 + enum Search_Value_Type + { + Search_Value_White, + Search_Value_Black, + }; + // 边缘搜索参数 + struct Edge_Search_Config + { + cv::Rect roi; // 边缘搜索区域 + Search_Value_Type searchValueType; // 搜索边缘了下,黑还是白 + Edge_DirectSign directSign; // 搜索方向 + int nValueThreshold; // 灰度阈值 + int nSearchCount; // 搜索点的个数 把roi 均分成多少个点。 + int nSearchrange; // 搜索范围,一般为单数,如果 1表示 搜索当前点,如果3表示 除了当前点,还有左右 点。5表示 从-2到2 + int stepCount; // 每个搜索点的步数 + int nLimit; // 连续搜索多个满足阈值的点后,停止搜索,当前搜索点 搜索成功。 + std::string strchannel; + Edge_Search_Config() + { + roi = cv::Rect(0, 0, 0, 0); + directSign = DirectSign_UP; + searchValueType = Search_Value_White; + nValueThreshold = 40; + nSearchCount = 30; + nSearchrange = 1; + stepCount = 2; + nLimit = 3; + strchannel = ""; + } + bool CheckConfigValid() + { + bool bRet = true; + if (roi.width <= 0 || roi.height <= 0) + { + printf("s1 \n"); + return false; + } + if (searchValueType < Search_Value_White || searchValueType > Search_Value_Black) + { + printf("s2 \n"); + return false; + } + if (directSign < 0 || directSign > 4) + { + printf("s3 \n"); + return false; + } + if (nValueThreshold < 0 || nValueThreshold > 255) + { + printf("s4 \n"); + return false; + } + if (nSearchCount < 0) + { + printf("s5 \n"); + return false; + } + if (stepCount < 0) + { + printf("s6 \n"); + return false; + } + if (nLimit < 0) + { + printf("s7 \n"); + return false; + } + return true; + } + }; + struct Line + { + cv::Point p1; + cv::Point p2; + Line() + { + p1 = cv::Point(0, 0); + p2 = cv::Point(0, 0); + } + }; + struct QX_Result + { + cv::Rect roi_src; + int area_pixel; + QX_Result() + { + roi_src = cv::Rect(0, 0, 0, 0); + area_pixel = 0; + } + }; + // 检测小区域的信息 + struct Det_ROI_Config + { + cv::Rect roi; + std::vector plist; + }; + struct Algin_Result + { + cv::Rect corpRoi; + int offtx; + int offty; + cv::Mat H; + Algin_Result() + { + Init(); + } + void Init() + { + corpRoi = cv::Rect(0, 0, 0, 0); + offtx = 0; + offty = 0; + if (!H.empty()) + { + H.release(); + } + + } + /* data */ + }; + + // 检测参数和结果 + struct DetConfigResult + { + + BaseCheckFunction *pBaseCheckFunction; + std::string strChannel; + std::vector qx_result; + std::vector edge_det_roi; + Algin_Result alginResult; + + std::vector Det_region; + bool bSaveResultImg; + DetConfigResult() + { + Init(); + } + void Init() + { + pBaseCheckFunction = NULL; + strChannel = ""; + qx_result.clear(); + edge_det_roi.clear(); + alginResult.Init(); + Det_region.clear(); + bSaveResultImg = false; + } + }; + + enum Det_ROI_Type + { + Det_ROI_Type_UP, + Det_ROI_Type_DOWN, + Det_ROI_Type_LEFT, + Det_ROI_Type_RIGHT, + }; + +public: + bool GetSegmentIntersection(const Line &l1, const Line &l2, cv::Point2f &intersection); + Edge_QX_Det(/* args */); + ~Edge_QX_Det(); + + int Detect(const cv::Mat &img, DetConfigResult *pDetConfig); + +private: + // 边缘点搜索函数 + int GetEdgePoint(const cv::Mat &img, Edge_Search_Config *pEdge_Search_Config, std::vector &pointList); + + int GetLine(const cv::Mat &img, std::vector &pointList, int lineNum, int xory, std::vector &lineList); + + // 检测缺陷 + int Det_qx(const cv::Mat &img, std::vector roilist, Det_ROI_Type type, DetConfigResult *pDetConfig); + + int applyMaskInROI(const cv::Mat &grayImg, const Det_ROI_Config &config, cv::Mat &result, int threshold); + + // 通过手绘的方式来检测 + int Draw_Det(const cv::Mat &img, DetConfigResult *pDetConfig); + +private: + /// @brief + /// @param img 搜到图片 单通道 + /// @param DirectSign 搜索方向 >0 正向,< 0 反向 + /// @param Gate 阈值 + /// @param BorW 搜索黑点 = 0还是白点 = 1 + /// @param roi 搜索范围 + /// @param StepCount 搜索点数 + /// @param Limit 最小满是阈值点个数算上搜索成功 + /// @return <0 搜索错误, >=0表示 搜索位置 + int UDNoiseEdgeDetect(cv::Mat img, int DirectSign, int Gate, int BorW, cv::Rect roi, int StepCount, int Limit); + /// @brief + /// @param img 搜到图片 单通道 + /// @param DirectSign 搜索方向 >0 正向,< 0 反向 + /// @param Gate 阈值 + /// @param BorW 搜索黑点 = 0还是白点 = 1 + /// @param roi 搜索范围 + /// @param StepCount 搜索点数 + /// @param Limit 最小满是阈值点个数算上搜索成功 + /// @return <0 搜索错误, >=0表示 搜索位置 + int LRNoiseEdgeDetect(cv::Mat img, int DirectSign, int Gate, int BorW, cv::Rect roi, int StepCount, int Limit); + // int LRNoiseEdgeDetect(cv::Mat img,int DirectSign, int Gate,int BorW, int StartSearchSite, int Step, int StepCount, int top, int bottom, int Limit, int Depth, int MaxLimit); + +private: + cv::Mat showimg; + bool bshowimg; + +private: + /* data */ +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/ImageAllResult.h b/AlgorithmModule/include/ImageAllResult.h new file mode 100644 index 0000000..a6e59b2 --- /dev/null +++ b/AlgorithmModule/include/ImageAllResult.h @@ -0,0 +1,97 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:49:50 + * @LastEditTime: 2025-09-23 10:45:58 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/include/CamDeal.h + */ +#ifndef ImageAllResult_H_ +#define ImageAllResult_H_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Define_Product.hpp" +#include "CheckErrorCodeDefine.hpp" +#include "ImgCheckConfig.h" +#include "ImageDetConfig.h" +#include "DetLog.h" +#include "CheckResultJson.h" +using namespace std; +using namespace cv; + +// 包含所有的图片检测结果,如 返回的结果,临时结果, 其他检测结果 +class ImageAllResult +{ +public: + enum DetStep + { + DetStep_NotDet, + DetStep_Deting, + DetStep_Complet, + }; + struct AI_Det_MaskImg + { + cv::Rect roi; + cv::Mat AI_inImg; + cv::Mat AI_mask; + }; + +private: + /* data */ +public: + ImageAllResult(/* args */); + ~ImageAllResult(); + + void AddLog(std::string str); + // 添加图片信息 + int AddDetImage(std::shared_ptr p); + DetStep getStep(); + void setStep(DetStep step); + bool IsNotDet(); + +public: + // 裁切大小 + cv::Rect CropRoi = cv::Rect(0, 0, 0, 0); + // 检测的原始图片 + cv::Mat detImg; + // AI 推理的mask图片 + cv::Mat AIMaskImg; + // 结果图片 + cv::Mat resultImg; + + float fscale_detToresult_x = 0; + float fscale_detToresult_y = 0; + + int NG_num = 0; + int YS_num = 0; + int Ok_num = 0; + int NoJudge_num = 0; + +public: + DetStep m_step = DetStep_NotDet; + std::string strBaseInfo = ""; + std::string strChannel = ""; + std::vector LogList; + std::shared_ptr detlog; + std::shared_ptr result; // 返回检测结果 + std::shared_ptr pDetResult; // 检测结果 后续主要对pDetResult 继续分析 + std::shared_ptr productBaseResult; // 产品相关的基本结果信息 + std::shared_ptr cameraBaseResult; // 相机相关的基本结果信息 + + std::vector> AI_Qx_MaskList; + std::mutex mtx_Det; // 互斥量 +private: + PRINT_LOG_ m_PrintLog; + + CheckResultJson m_CheckResultJson; +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/ImageDetBase.h b/AlgorithmModule/include/ImageDetBase.h new file mode 100644 index 0000000..627251e --- /dev/null +++ b/AlgorithmModule/include/ImageDetBase.h @@ -0,0 +1,55 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-09-11 15:32:52 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-14 17:41:14 + * @FilePath: /BOE_CELL_AOI_Detect/AlgorithmModule/include/ImageDetBase.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#ifndef ImageDetBase_H_ +#define ImageDetBase_H_ +#include +#include +#define INTERFACE_Det_VERSION 4 + +/*******************一般调用流程*************************************************************************************************************************/ +/*******************1、初始化 UpdateConfig*************************************************************************************************************************/ +/*******************2、初始化 Init 并开启 *************************************************************************************************************************/ +/*******************3、GetStatus 获取状态 如果 =CHECK_THREAD_STATUS_IDLE 可以设置检测数据并开启检测 SetDataRun***************************************************/ +/*******************4、GetStatus 获取状态 如果 =CHECK_THREAD_STATUS_COMPLETE 检测完成,可以获取检测结果 GetCheckReuslt 拷贝检测结果 自动把状态设为 CHECK_THREAD_STATUS_IDLE*****************************/ +struct ImageDetconfig; +struct ImageDetResult; +struct ImageAllResult; +class ImgCheckBase +{ +protected: + ImgCheckBase() {} + +public: + // delete camera interface + ~ImgCheckBase() {} + static ImgCheckBase *GetInstance(); + // 初始化参数 pconfig 参数指针 返回:0 成功 其他异常 + virtual int RunStart(void *pconfig1 = NULL) = 0; + + // 设置检测数据,并开启检测 返回:0 成功 其他异常 + virtual int SetDataRun_SharePtr(std::shared_ptr p) = 0; + + // 获取结果信息 返回:0 成功 其他异常 + virtual int GetCheckReuslt(std::shared_ptr &pResult) = 0; + + virtual int CheckImg(std::shared_ptr p, std::shared_ptr &pResult) = 0; + virtual int ReJsonResul(std::shared_ptr p, std::shared_ptr &pResult) = 0; + + // 获取检测库 状态信息 返回:CHECK_THREAD_RUN_STATUS + virtual int GetStatus() = 0; + + // 更新参数 pconfig 参数指针,nConfigType 需要更新的参数类型 返回:0 成功 其他异常 + virtual int UpdateConfig(void *pconfig, int nConfigType) = 0; + + // 返回检测版本信息 + virtual std::string GetVersion() = 0; + // 返回错误信息 + virtual std::string GetErrorInfo() = 0; +}; +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/ImageDetConfig.h b/AlgorithmModule/include/ImageDetConfig.h new file mode 100644 index 0000000..3e9acd1 --- /dev/null +++ b/AlgorithmModule/include/ImageDetConfig.h @@ -0,0 +1,364 @@ + + +#ifndef _ImageDetConfig_HPP_ +#define _ImageDetConfig_HPP_ + +#include +#include +#include "ImgCheckConfig.h" +#include "CheckErrorCodeDefine.hpp" +#include "DetLog.h" + +#define QX_SAMLLIMG_WIDTH 160 +#define QX_SAMLLIMG_HEIGHT 160 + +// 缺陷结果信息 +struct QX_ERROR_INFO_ +{ + int Idx; + int result; + std::string result_name; + cv::Rect roi; + int area; + int energy; + float JudgArea; + float JudgArea_second; + float flen; + float fbreadth; + int nconfig_qx_type; + std::string qx_name; + int maxValue; + int whiteOrBlack; + float grayDis; + float fUpIou; + float density; // Blob- 密度 + std::vector detLogList; // 检测日志 + std::shared_ptr detlog; + std::vector detRegionidxList; // 对应检测区域的 idx. + QX_ERROR_INFO_() + { + Init(); + } + ~QX_ERROR_INFO_() + { + } + void Init() + { + whiteOrBlack = 0; + Idx = 0; + area = 0; + energy = 0; + JudgArea = 0; + JudgArea_second = 0; + flen = 0; + nconfig_qx_type = 0; + qx_name = ""; + maxValue = 0; + grayDis = 0; + fUpIou = 0; + result = 0; + result_name = "OK"; + density = 0; + cv::Rect roi = cv::Rect(0, 0, 0, 0); + detLogList.erase(detLogList.begin(), detLogList.end()); + detLogList.clear(); + detRegionidxList.clear(); + detlog = std::make_shared(); + } + void print(std::string str = "") + { + std::cout << str << ": " + << "Idx: " << Idx + << ", Result: " << result << " " << result_name + << ", ROI: (" << roi.x << ", " << roi.y << ", " << roi.width << ", " << roi.height << ")" + << ", Area: " << area + << ", Energy: " << energy + << ", JudgArea: " << JudgArea + << ", JudgArea second: " << JudgArea_second + << ", density: " << density + << ", Flen: " << flen + << ", nconfig_qx_type: " << nconfig_qx_type + << ", QX Name: " << qx_name + << ", Max Value: " << maxValue + << ", Gray Dis: " << grayDis + << ", fUpIou: " << fUpIou + << ", whiteOrBlack: " << whiteOrBlack + << std::endl; + } +}; +struct One_Image_CheckResult_ +{ + + cv::Rect CutRoi; // 当前检测图片 对应的裁切区域 + cv::Rect Param_CropRoi; // 参数模版 对应的裁切区域 + std::shared_ptr> pQx_ErrorList; // 缺陷错误信息 + void print(std::string str = "") + { + std::cout << str << ": " + << " CutRoi: (" << CutRoi.x << ", " << CutRoi.y << ", " << CutRoi.width << ", " << CutRoi.height << ")" + << std::endl; + + std::cout << str << ": " + << " Param_CropRoi: (" << Param_CropRoi.x << ", " << Param_CropRoi.y << ", " << Param_CropRoi.width << ", " << Param_CropRoi.height << ")" + << std::endl; + + for (int i = 0; i < pQx_ErrorList->size(); i++) + { + pQx_ErrorList->at(i).print(std::to_string(i)); + } + } +}; +// 定位结果 +struct Align_Result +{ + bool bDet; // 检测状态 true 成功,false 失败。 + bool bUse; // 是否要使用。 + bool bDraw; // 是否绘制 + + cv::Point bestMatch; + int offt_x; // 偏移值 + int offt_y; // 偏移值 + float fCropROI_Scale_ParmToDet_X; // 裁剪区域的缩放 + float fCropROI_Scale_ParmToDet_Y; // 裁剪区域的缩放 + + std::vector feature_PointList_DetImg; // 特征区域点 检查图上的特征点 + cv::Rect Crop_Roi_DetImg; // 检测图片上的 裁切区域 + cv::Rect Crop_Roi_ParmImg; // 参数图片上的 裁切区域 + + Align_Result() + { + Init(); + } + void Init() + { + bDet = false; + bUse = false; + offt_x = 0; + offt_y = 0; + bestMatch = cv::Point(0, 0); + fCropROI_Scale_ParmToDet_X = 1; + fCropROI_Scale_ParmToDet_Y = 1; + feature_PointList_DetImg.clear(); + Crop_Roi_DetImg = cv::Rect(0, 0, 0, 0); + Crop_Roi_ParmImg = cv::Rect(0, 0, 0, 0); + bDraw = false; + } + void copy(Align_Result tem) + { + this->bDet = tem.bDet; + this->bUse = tem.bUse; + this->offt_x = tem.offt_x; + this->offt_y = tem.offt_y; + this->fCropROI_Scale_ParmToDet_X = tem.fCropROI_Scale_ParmToDet_X; + this->fCropROI_Scale_ParmToDet_Y = tem.fCropROI_Scale_ParmToDet_Y; + this->bDraw = tem.bDraw; + this->bestMatch = tem.bestMatch; + this->Crop_Roi_DetImg = tem.Crop_Roi_DetImg; + this->Crop_Roi_ParmImg = tem.Crop_Roi_ParmImg; + this->feature_PointList_DetImg.assign(tem.feature_PointList_DetImg.begin(), tem.feature_PointList_DetImg.end()); + } + // 从检测图的原始图片 映射到 参数的原始图 + cv::Point Det_srcToParm_src_Point(cv::Point &p) + { + cv::Point dst_p; + dst_p.x = (p.x - offt_x) / fCropROI_Scale_ParmToDet_X; + dst_p.y = (p.y - offt_y) / fCropROI_Scale_ParmToDet_Y; + return dst_p; + } + cv::Rect Det_srcToParm_src_Rect(cv::Rect &roi) + { + cv::Rect dst_roi; + cv::Point src_pl = cv::Point(roi.x, roi.y); + cv::Point src_rb = cv::Point(roi.x + roi.width, roi.y + roi.height); + cv::Point p_lt = Det_srcToParm_src_Point(src_pl); + cv::Point p_rb = Det_srcToParm_src_Point(src_rb); + dst_roi.x = p_lt.x; + dst_roi.y = p_lt.y; + dst_roi.width = p_rb.x - p_lt.x; + dst_roi.height = p_rb.y - p_lt.y; + + return dst_roi; + } + // 参数的原始图 映射到 检测图的原始图片 + cv::Point Parm_srcToDet_src_Point(cv::Point &p) + { + cv::Point dst_p; + dst_p.x = p.x * fCropROI_Scale_ParmToDet_X + offt_x; + dst_p.y = p.y * fCropROI_Scale_ParmToDet_Y + offt_y; + return dst_p; + } + cv::Rect Parm_srcToDet_src_Rect(cv::Rect &roi) + { + cv::Rect dst_roi; + cv::Point src_pl = cv::Point(roi.x, roi.y); + cv::Point src_rb = cv::Point(roi.x + roi.width, roi.y + roi.height); + cv::Point p_lt = Parm_srcToDet_src_Point(src_pl); + cv::Point p_rb = Parm_srcToDet_src_Point(src_rb); + dst_roi.x = p_lt.x; + dst_roi.y = p_lt.y; + dst_roi.width = p_rb.x - p_lt.x; + dst_roi.height = p_rb.y - p_lt.y; + + return dst_roi; + } + // 参数图片上的点 对应到 检测裁切后上的点 + cv::Point Parm_srcToDet_Crop_Point(cv::Point &p) + { + cv::Point dst_p = Parm_srcToDet_src_Point(p); + dst_p.x -= Crop_Roi_DetImg.x; + dst_p.y -= Crop_Roi_DetImg.y; + return dst_p; + } + // 参数图片上的点 对应到 检测裁切后上的点 + cv::Rect Parm_srcToDet_Crop_Rect(cv::Rect &roi) + { + cv::Rect dst_roi; + cv::Point src_pl = cv::Point(roi.x, roi.y); + cv::Point src_rb = cv::Point(roi.x + roi.width, roi.y + roi.height); + cv::Point p_lt = Parm_srcToDet_Crop_Point(src_pl); + cv::Point p_rb = Parm_srcToDet_Crop_Point(src_rb); + dst_roi.x = p_lt.x; + dst_roi.y = p_lt.y; + dst_roi.width = p_rb.x - p_lt.x; + dst_roi.height = p_rb.y - p_lt.y; + + return dst_roi; + } + void CalOfftScal() + { + cv::Point src_pl = cv::Point(Crop_Roi_DetImg.x, Crop_Roi_DetImg.y); + cv::Point src_rb = cv::Point(Crop_Roi_DetImg.x + Crop_Roi_DetImg.width, Crop_Roi_DetImg.y + Crop_Roi_DetImg.height); + + cv::Point param_pl = cv::Point(Crop_Roi_ParmImg.x, Crop_Roi_ParmImg.y); + cv::Point param_rb = cv::Point(Crop_Roi_ParmImg.x + Crop_Roi_ParmImg.width, Crop_Roi_ParmImg.y + Crop_Roi_ParmImg.height); + + int a_x_1 = src_pl.x; + int a_x_2 = src_rb.x; + + int b_x_1 = param_pl.x; + int b_x_2 = param_rb.x; + + int diff_a_x = a_x_1 - a_x_2; + int diff_b_x = b_x_1 - b_x_2; + float fscale_x = 1; + if (diff_b_x != 0) + { + fscale_x = diff_a_x * 1.0f / diff_b_x; + } + int ofx = a_x_1 - fscale_x * b_x_1; + + // printf("a_x_1 %d a_x_2 %d\n", a_x_1, a_x_2); + // printf("b_x_1 %d b_x_2 %d\n", b_x_1, b_x_2); + // printf("fscale_x %f ofx %d \n", fscale_x, ofx); + + int a_y_1 = src_pl.y; + int a_y_2 = src_rb.y; + + int b_y_1 = param_pl.y; + int b_y_2 = param_rb.y; + + int diff_a_y = a_y_1 - a_y_2; + int diff_b_y = b_y_1 - b_y_2; + float fscale_y = 1; + if (diff_b_y != 0) + { + fscale_y = diff_a_y * 1.0f / diff_b_y; + } + int ofy = a_y_1 - fscale_y * b_y_1; + + // printf("a_y_1 %d a_y_2 %d\n", a_y_1, a_y_2); + // printf("b_y_1 %d b_y_2 %d\n", b_y_1, b_y_2); + // printf("fscale_y %f ofy %d \n", fscale_y, ofy); + + offt_x = ofx; + offt_y = ofy; + fCropROI_Scale_ParmToDet_X = fscale_x; + fCropROI_Scale_ParmToDet_Y = fscale_y; + } + void print() + { + printf("scale x %f y %f ,offt x %d y %d\n", fCropROI_Scale_ParmToDet_X, fCropROI_Scale_ParmToDet_Y, offt_x, offt_y); + } +}; +// 产品相关的 基础检测结果 +struct ProductBaseResult +{ + std::string strproductName = ""; // 产品 ID + std::shared_ptr detlog; +}; +// 相机相关的 基础检测结果 +struct CameraBaseResult +{ + std::string strCameraName = ""; // 相机结果 ID +}; +struct ImageDetconfig +{ + cv::Mat ShieldMaskImg; // 屏蔽mask + cv::Mat UpMaskImg; // Up 画面 mask图片 + cv::Mat DPMaskImg; + cv::Mat edge_maskImg; + bool bUseUpMaskImg; + std::shared_ptr> pZF_roiList; // 字符的区域 + + std::shared_ptr pBaseImgCheckConfig; + Align_Result alignResult; // 定位结果 + ImageDetconfig() + { + Init(); + } + ~ImageDetconfig() + { + } + void Init() + { + bUseUpMaskImg = false; + if (!ShieldMaskImg.empty()) + { + ShieldMaskImg.release(); + } + if (!UpMaskImg.empty()) + { + UpMaskImg.release(); + } + if (!DPMaskImg.empty()) + { + DPMaskImg.release(); + } + if (!edge_maskImg.empty()) + { + edge_maskImg.release(); + } + alignResult.Init(); + } +}; + +struct ImageDetResult +{ + bool bShield_ZF; // 是否要屏蔽字符区域 + bool bUseUpImg; // 是否要使用 up img 进行过滤 + cv::Mat AI_maskImg; + int Yx_result; // 异显检测状态 + float fUP_IOU; // UP 画面 使用的 iou + std::shared_ptr> pZF_roiList; // 字符的区域 + std::shared_ptr pOneImgDetResult; // 单图检测结果 + std::shared_ptr pBaseImgCheckResult; + ImageDetResult() + { + Init(); + } + ~ImageDetResult() + { + } + void Init() + { + bShield_ZF = false; + if (!AI_maskImg.empty()) + { + AI_maskImg.release(); + } + Yx_result = 0; + fUP_IOU = 0; + bUseUpImg = false; + } +}; +#endif //_CORELOGICFACTORY_HPP_ \ No newline at end of file diff --git a/AlgorithmModule/include/ImageResultJudge.h b/AlgorithmModule/include/ImageResultJudge.h new file mode 100644 index 0000000..b06697c --- /dev/null +++ b/AlgorithmModule/include/ImageResultJudge.h @@ -0,0 +1,208 @@ +/* +//图片基本处理 + */ +#ifndef ImageResultJudge_H_ +#define ImageResultJudge_H_ +#include "CheckConfigDefine.h" +#include +#include +#include +#include +#include +#include +#include "Define_Base.h" +#include "ImgCheckBase.h" +#include "ImageDetBase.h" +#include "ImgCheckConfig.h" +#include "CheckErrorCodeDefine.hpp" +#include "ConfigBase.h" +#include "CheckConfigDefine.h" +#include "ImageDetConfig.h" +#include "Define_Product.hpp" +#include "CameraResult.h" +#include "DetLog.h" +class ImageResultJudge +{ +private: + enum DrawType + { + Draw_rect, + Draw_circle, + Draw_str, + }; + struct txtDrawBackgroundk + { + std::vector txtDrawRoi; + cv::Rect findNonOverlappingPos( + const cv::Rect &newRect, + int step = 5, + int maxRadius = 800) + { + // 如果本身就不重叠,直接返回 + bool overlap = false; + for (const auto &r : txtDrawRoi) + { + if ((newRect & r).area() > 0) + { + overlap = true; + break; + } + } + if (!overlap) + return newRect; + // 螺旋搜索 + for (int radius = step; radius <= maxRadius; radius += step) + { + for (int dx = -radius; dx <= radius; dx += step) + { + for (int dy = -radius; dy <= radius; dy += step) + { + cv::Rect candidate = newRect + cv::Point(dx, dy); + bool conflict = false; + for (const auto &r : txtDrawRoi) + { + if ((candidate & r).area() > 0) + { + conflict = true; + break; + } + } + if (!conflict) + { + return candidate; // 找到合适位置 + } + } + } + } + printf("find fail ============= \n"); + // 实在找不到,就返回原始位置 + return newRect; + } + }; + struct DrawInfo + { + cv::Mat drawImg; + DrawType type = Draw_rect; + std::vector strlist; + cv::Point txtP = cv::Point(0, 0); + cv::Rect roi = cv::Rect(0, 0, 0, 0); + cv::Scalar color = cv::Scalar(255, 0, 255); + cv::Point cp = cv::Point(0, 0); + int dr = 0; + float txtsize = 0.8; + std::shared_ptr txtbackgroundk; + }; + + struct singleQxInfo{ + int qxidx; + int ng_type; + cv::Point pcenter; + singleQxInfo(int qxidx, int ng_type, cv::Point pcenter):qxidx(qxidx),ng_type(ng_type),pcenter(pcenter){} + }; + struct singleQxZoningInfo{ + float scale_X; + float scale_Y; + float judge_dis; + int judge_num; + Point center; + vector qxList; + void Init(){ + scale_X = 0; + scale_Y = 0; + judge_dis = 0; + judge_num = 0; + center = Point(0, 0); + qxList.clear(); + } + float calulateDisSquared(cv::Point pcenter){ + float dx = (pcenter.x - center.x) * scale_X; + float dy = (pcenter.y - center.y) * scale_Y; + return (pow(dx, 2) + pow(dy, 2)); + } + // 由距离来卡控添加缺陷,并更新区域center坐标 + bool Insert(singleQxInfo qxInfo){ + if(qxList.size() == 0) + { + center = qxInfo.pcenter; + qxList.push_back(qxInfo); + return true; + } + else + { + if(calulateDisSquared(qxInfo.pcenter) < judge_dis * judge_dis) + { + center = Point((qxInfo.pcenter.x + center.x) / 2, (qxInfo.pcenter.y + center.y) / 2); + qxList.push_back(qxInfo); + return true; + } + else return false; + } + } + bool judgeNum(){ + if(qxList.size() >= judge_num) return true; + else return false; + } + }; + struct usenumQxZoningInfo{ + vector singleQxZoningList; + }; + struct ictQxZoningInfo{ + vector usenumQxZoningList; + }; + struct iregionQxZoningInfo{ + vector ictQxZoningList; + }; +public: + ImageResultJudge(/* args */); + ~ImageResultJudge(); + + int SetAnalysisyConfig(AnalysisyConfigST *pAnalysisyConfig); + int ResultJudge(std::shared_ptr pImageResult); + int UpdateConfig(); + int DrawResult(std::shared_ptr pImageResult); + +private: + // 获取 缺陷在参数列表的位置 + int GetParamidx(); + int UpdateImgageScale(); + + int addInDrawBlob(int errortype, int blobidx, QX_ERROR_INFO_ *QX_info, float fs_resize_x, float fs_resize_y); + // 参数缺陷类型转 结果参数类型 + int ConfigTypeToResultType(int nconfigType); + cv::Rect GetCutRoi(cv::Rect &roi, const cv::Mat &img); + // 获取缺陷 对应的AI输入 输出图片, + int GetAIDetImg(std::shared_ptr pImageResult, cv::Point pcenter, cv::Mat &AI_InImg, cv::Mat &AI_OutImg); + + int sendTask(std::shared_ptr task); + + std::shared_ptr GetTask(); + + void ThreadDraw(); + int DrawResultTask(std::shared_ptr task); + + // 等待 绘制完成 + int WaiteDrawComplate(); + +private: + bool m_bExit; + float m_fImgage_Scale_X = 0.1; + float m_fImgage_Scale_Y = 0.1; + // 检测分析参数 + AnalysisyConfigST *m_pAnalysisyConfig; + CommonConfigNodeST *m_pCommonAnalysisyConfig; + ALLChannelCheckFunction *m_pChannelFuntion; // 画面检测功能 + BaseCheckFunction *m_pbaseCheckFunction; // 基础检测 + RegionConfigST *m_pRegionAnalysisyParam; // 分析参数 + BasicConfig *m_pBasicConfig; + + // 检查缺陷对应参数中的位置。 + int m_QxInParamListIdx[CONFIG_QX_NAME_count]; + + std::queue> m_DrawInfoList; + std::mutex m_task_mutex_; + std::condition_variable m_task_cv_; + std::shared_ptr ptr_thread_Draw; + std::condition_variable m_drawComplate_cv_; +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/ImageStorage.h b/AlgorithmModule/include/ImageStorage.h new file mode 100644 index 0000000..5b62c6d --- /dev/null +++ b/AlgorithmModule/include/ImageStorage.h @@ -0,0 +1,44 @@ +#ifndef IMAGE_STORAGE_H +#define IMAGE_STORAGE_H + +#include +#include +#include +#include +#include +#include + +class ImageStorage { +private: + std::queue> imageQueue; + std::mutex queueMutex; + std::condition_variable cv; + std::thread storageThread; + + static ImageStorage* instance; // 静态成员指针,存储单例对象 + + bool stopFlag; + + // 私有构造函数和析构函数,防止外部创建实例 + ImageStorage(); + ~ImageStorage(); + + // 存储线程的工作函数 + void storeImages(); + +public: + // 获取单例实例 + static ImageStorage* getInstance(); + + // 禁止拷贝构造和赋值 + ImageStorage(const ImageStorage&) = delete; + ImageStorage& operator=(const ImageStorage&) = delete; + + // 添加图片到队列 + int addImage(const std::string &path,const cv::Mat &image,bool badd = false); + + // 停止存储线程 + void stop(); +}; + +#endif // IMAGE_STORAGE_H diff --git a/AlgorithmModule/include/ImgCheckAnalysisy.hpp b/AlgorithmModule/include/ImgCheckAnalysisy.hpp new file mode 100644 index 0000000..c501e6b --- /dev/null +++ b/AlgorithmModule/include/ImgCheckAnalysisy.hpp @@ -0,0 +1,291 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:49:50 + * @LastEditTime: 2025-09-17 19:49:41 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/include/CamDeal.h + */ +#ifndef ImgCheckAnalysisy_H_ +#define ImgCheckAnalysisy_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "BlobBase.h" +#include "ImgCheckBase.h" +#include "ImageDetBase.h" +#include "ImgCheckConfig.h" +#include "CheckErrorCodeDefine.hpp" +#include "CheckConfigDefine.h" +#include "ConfigBase.h" +#include "ImageDetConfig.h" +#include "OtherDetect.h" +#include "Define_Error.h" +#include "Edge_QX_Det.h" +#include "AI_Edge_Algin.h" +#include "AI_Factory.h" +#include "ImageAllResult.h" +#include "Task.h" + +using namespace std; +using namespace cv; + +enum AT_THRESHOLD_TYPE_ +{ + AT_THRESHOLD_TYPE_NULL, + AT_THRESHOLD_TYPE_READY, + AT_THRESHOLD_TYPE_BUSY, + AT_THRESHOLD_TYPE_COMPLETE, +}; + +// 全局静态变量, 记录图像灰度值异常累计数量 +static int g_nImgBrightnessErrorCount = 0; +class ImgCheckAnalysisy : public ImgCheckBase +{ + +public: + ImgCheckAnalysisy(); + ~ImgCheckAnalysisy(); + + // 初始化参数 pconfig 参数指针 返回:0 成功 其他异常 + int RunStart(void *pconfig1); + + // 设置检测数据,并开启检测 返回:0 成AT_THRESHOLD_TYPE_READY功 其他异常 + int SetDataRun_SharePtr(std::shared_ptr p); + + // 获取结果信息 返回:0 成功 其他异常 + int GetCheckReuslt(std::shared_ptr &pResult); + + int CheckImg(std::shared_ptr p, std::shared_ptr &pResult); + int ReJsonResul(std::shared_ptr p, std::shared_ptr &pResult); + // 获取检测库 状态信息 返回:CHECK_THREAD_RUN_STATUS + int GetStatus(); + + // 更新参数 pconfig 参数指针,nConfigType 需要更新的参数类型 返回:0 成功 其他异常 + int UpdateConfig(void *pconfig, int nConfigType); + + std::string GetVersion(); + + std::string GetErrorInfo(); + + int creatsavedir(); + +private: + // 加载运行参数 + int LoadRunConfig(void *p); + + // 加载分析参数 + int LoadCheckConfig(void *p); + + /// @brief 初始化并且启动程序 + /// @return + int InitRun(int nId); + + /// @brief 开启检测 + /// @return + int StartCheck(); + + /// @brief 设置空闲 + /// @return + int SetIDLE(); + +private: + // 开启线程 + int StartThread(int nId); + // 停止线程 + int StopThread(); + + // 退出系统 + int ExitSystem(); + + // 初始化模型 + int InitModel(); + + cv::Scalar calc_blob_info_withstats(cv::Mat &img, const cv::Mat &mask, cv::Rect &stats, cv::Size k_size = cv::Size(5, 5), int expand = 10, double threshold = 0.7); + // 检测 + int CheckRun(); + int AI_Edge(const cv::Mat &img, cv::Rect &cutRoi); + // 计算产品尺寸 + int CalProductSize(); + // 图片预处理 + int ImgPreDet(); + + // 设置新的检测参数 + int SetNewConfig(); + + ChannelCheckFunction *GetChannelFuntion(std::string strChannelName); // 获得 通道的检测功能 + +private: + // 图片处理线程 + std::shared_ptr ptr_thread_Run; + int Run(int nId); // 运行; + + // 图片处理线程 + std::shared_ptr ptr_thread_AI; + + int set_cpu_id(const std::vector &cpu_set_vec); + + // 计算BLob 其他一些属性值。 + int CalBlob_Other(); + + // 分类 + + int GetClassImg(const cv::Mat &img, cv::Mat &AIdetImg, cv::Rect qx_roi, int detwidth, int detheight); + + // 计算缺陷长度 + vector Cal_QXLen(cv::Mat qx_maskImg, int qx_type, float fsc_x, float fsc_y); + + // 获取检测结果blob,用于后续分析。 + int GetCheckResultBLob(); + + // 获得所有blob + int GetALLBlob(); + + // 对AI mask图片进行 结果处理 + int AIMaskDet(); + + // 轮廓处理 + int Contours(); + + // 检测初始化 + int CheckImgInit(); + // 参数 核对 + int ConfigCheck(cv::Mat img); + // 多线程方式处理 + int AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg); + // 缺陷分类 + int AI_QX_Class_Thread(); + + // 多线程 任务运行管理器 + int ThreadTask(int nId); // 运行; + // resize 图片 + int ResizeImg(); + + // AI 推理任务函数 + void TaskFun_AIDet(std::shared_ptr task); + // 缺陷分类任务函数 + void TaskFun_QxClass(std::shared_ptr task); + + // 更新 检测区域 + int Update_DetRoiList(); + + // 临时绘制结果 + int DrawResult_Step_1(); + + // 参数缺陷类型转 结果参数类型 + int AIClassTypeToConfigType(int nAIQXType); + + // 更新成像精度 + int UpdateImgageScale(); + + // 边缘缺陷检测 + int Edge_Qx_Det(const cv::Mat &img); + + // 把blob 汇总成 检测结果。 + int BLobToDetResult(); + + //自适应参数区域更新 + int Adapt_Config(Mat img, Rect roi, bool b_update); + + std::shared_ptr AI_Factory; + +private: + int m_nErrorCode; // 错误代码 + bool m_bInitSucc; // 初始化状态 + bool m_bExit; // 是否退出检测 + int m_nThreadIdx; // 线程序号 //相机处理的顺序号,该序号 程序运行就已经固定 + + std::shared_ptr runner; + // 所有的检测结果 + std::shared_ptr m_pImageAllResult; + std::shared_ptr m_pdetlog; + std::shared_ptr m_pDetResult; // 检测结果 后续主要对pDetResult 继续分析 + std::shared_ptr DetImgInfo_shareP; + + // 检测结果 + std::shared_ptr m_CheckResult_shareP; + + // 检测参数模块 + ConfigBase *m_pConfig; + bool m_bupdateconfig; + int m_nConfigIdx; + // 线程运行的一些参数 + RunInfoST m_RunConfig; + + float m_fImgage_Scale_X; + float m_fImgage_Scale_Y; + + // 分析参数 + AnalysisyConfigST m_AnalysisyConfig; + ChannelCheckFunction *m_pFuntion; + BaseCheckFunction *m_pbaseCheckFunction; // 基础检测 + CommonConfigNodeST *m_pCommonAnalysisyConfig; + BasicConfig *m_pBasicConfig; + RegionConfigST *m_pRegionAnalysisyParam; // 分析参数 + int m_QxInParamListIdx[CONFIG_QX_NAME_count]; + + cv::Rect m_CutRoi; + cv::Rect m_Crop_Roi_paramImg; // 裁切在参数模板图上的 位置。 + + std::string m_strCurDetChannel; // 当前处理的图片通道 + + // // 检测控制参数 + // CheckControlConfigSt *m_pcheckControlConfig; + int m_nRun_Status; // 运行状态:空闲,运行中,异常,。。。。。 + + int m_nCheckResultErrorCode; + + Detect_ROI_Config m_DetRoiList; // 检测区域roi List + + ERROR_DOTS_BLOBS blobs; + + OtherDet_Config m_OtherDet_Config; + + AI_Edge_Algin m_pAI_Edge_Algin; + // 边缘定位结果 + std::shared_ptr m_pEdge_Align_Result; + + Edge_QX_Det m_Edge_QX_Det; + Edge_QX_Det::DetConfigResult m_Edge_DetConfig; + std::vector m_Draw_qxImageResult; // 缺陷小图结果 + + std::vector SmallRoiList; + + std::string m_strRootPath_TA_cls; + std::string m_strRootPath_CA_cls; + std::string m_strSavePath_cls; + std::string m_strLastDate; + + ImageStorage *m_pImageStorage; + + // AI 推理的所有结果, 可能会返回去。需要临时存储。 + std::queue> m_AIMaskImgBLobQueue; + std::mutex mtx_AIMaskImgBLobQueue; + + Task m_task; + std::shared_ptr m_AItask; + std::shared_ptr m_Classtask; // 缺陷分类任务 + + // AI mask 在这一列是否有 缺陷残点,用以 加速 blob 分析。 + unsigned char *m_ImgBlobHFlagData; + + // 原始区域数据 + Rect m_old_productROI = Rect(0, 0, 0, 0); + std::vector m_old_cur_edgeDet_region; + std::vector m_old_cur_markLine_region; + cv::Point m_old_cur_markLine_mark1; + cv::Point m_old_cur_markLine_mark2; + std::vector m_old_cur_regionConfigArr; +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/ImgCheckBase.h b/AlgorithmModule/include/ImgCheckBase.h new file mode 100644 index 0000000..771dfd8 --- /dev/null +++ b/AlgorithmModule/include/ImgCheckBase.h @@ -0,0 +1,94 @@ +#ifndef ImgCheckBase_H_ +#define ImgCheckBase_H_ +#include +#include +#define ALL_INTERFACE_VERSION 4 + +enum CHECK_THREAD_RUN_STATUS +{ + CHECK_THREAD_STATUS_IDLE, // 空闲 0 + CHECK_THREAD_STATUS_READY, // 准备好了 1 + CHECK_THREAD_STATUS_BUSY, // 运行中 2 + CHECK_THREAD_STATUS_COMPLETE, // 检测完成 3 + CHECK_THREAD_STATUS_ERROR, // 运行错误 4 +}; +struct RunInfoST +{ + int nThreadIdx; // 线程号id + int nDeviceId; // GPU 设备 号 0 或 1 + int nCpu_start_Idx; // 绑定cpu 核号, + int nCpu_num; // 8 至少需要 8个 + bool bSaveCheckImg; // 是否存储 + bool bRetest; // 是否是复测标志,复测不需要加载模型 + int flag1; + int flag2; + std::string str1; + std::string str2; + RunInfoST() + { + nThreadIdx = 0; + nDeviceId = 0; + nCpu_start_Idx = 0; + nCpu_num = 8; + flag1 = 0; + flag2 = 0; + bRetest = false; + str1 = ""; + str2 = ""; + bSaveCheckImg = false; + } + void copy(RunInfoST tem) + { + this->nDeviceId = tem.nDeviceId; + this->nThreadIdx = tem.nThreadIdx; + this->nCpu_start_Idx = tem.nCpu_start_Idx; + this->nCpu_num = tem.nCpu_num; + this->bSaveCheckImg = tem.bSaveCheckImg; + this->flag1 = tem.flag1; + this->flag2 = tem.flag2; + this->bRetest = tem.bRetest; + this->str1 = tem.str1; + this->str2 = tem.str2; + } +}; +/*******************一般调用流程*************************************************************************************************************************/ +/*******************1、初始化 UpdateConfig*************************************************************************************************************************/ +/*******************2、初始化 Init 并开启 *************************************************************************************************************************/ +/*******************3、GetStatus 获取状态 如果 =CHECK_THREAD_STATUS_IDLE 可以设置检测数据并开启检测 SetDataRun***************************************************/ +/*******************4、GetStatus 获取状态 如果 =CHECK_THREAD_STATUS_COMPLETE 检测完成,可以获取检测结果 GetCheckReuslt 拷贝检测结果 自动把状态设为 CHECK_THREAD_STATUS_IDLE*****************************/ +struct shareImage; +struct CheckResult; +class ALLImgCheckBase +{ +protected: + ALLImgCheckBase() {} + +public: + // delete camera interface + ~ALLImgCheckBase() {} + static ALLImgCheckBase *GetInstance(); + // 初始化参数 pconfig 参数指针 返回:0 成功 其他异常 + virtual int RunStart(void *pconfig1 = NULL) = 0; + + // 设置检测数据,并开启检测 返回:0 成功 其他异常 + virtual int SetDataRun_SharePtr(std::shared_ptr p) = 0; + + // 获取结果信息 返回:0 成功 其他异常 + virtual int GetCheckReuslt(std::shared_ptr &pResult) = 0; + + virtual int CheckImg(std::shared_ptr p, std::shared_ptr &pResult) = 0; + + // 获取检测库 状态信息 返回:CHECK_THREAD_RUN_STATUS + virtual int GetStatus() = 0; + + // 更新参数 pconfig 参数指针,nConfigType 需要更新的参数类型 返回:0 成功 其他异常 + virtual int UpdateConfig(void *pconfig, int nConfigType) = 0; + + // 返回检测版本信息 + virtual std::string GetVersion() = 0; + // 返回错误信息 + virtual std::string GetErrorInfo() = 0; + + static ALLImgCheckBase *instance; +}; +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/ImgCheckConfig.h b/AlgorithmModule/include/ImgCheckConfig.h new file mode 100644 index 0000000..b55b88e --- /dev/null +++ b/AlgorithmModule/include/ImgCheckConfig.h @@ -0,0 +1,460 @@ +/* + * @Descripttion: + * @version: + * @Author: sueRimn + * @Date: 2022-03-16 17:09:11 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-23 10:15:49 + */ +/***********************************************/ +/************ ***************/ +/************金佰利检测算法参数定义**************/ +/************ **************/ +/**********************************************/ +#ifndef _ImgCheckConfig_HPP_ +#define _ImgCheckConfig_HPP_ +#include +#include +#include // unordered_map +#define RESULT_VERSION 31 + +#define MAX_BLOB_NUM 200 + +// 输入模型图片尺寸 +#define SRCIMG_WIDTH 14200 +#define SRCIMG_HEIGHT 10640 + +#define CHECKIMG_HEIGHT 2000 +#define CHECKIMG_WIDTH 4000 + +#define MASK_IMG_STEP 16 +#define MASK_IMG_STARTVALUE 48 + +// 检测日志 等级 +enum DET_LOG_LEVEL_ +{ + DET_LOG_LEVEL_0, // 极简信息 + DET_LOG_LEVEL_1, // 包含检测关键信息 + DET_LOG_LEVEL_2, // 关键信息+ 一般节点信息 + DET_LOG_LEVEL_3, // 详细信息 +}; +struct VERSION_INFO +{ + int ConfigVersion = 0; + int ResultVersion = RESULT_VERSION; + int InterfaceVersion = 0; +}; +// 检测错误代码 +enum ERROR_TYPE_ +{ + ERROR_TYPE_OK, // 1 疑是 + ERROR_TYPE_aotudian, // 2 凹凸点 + ERROR_TYPE_other, // 3 其他 + ERROR_TYPE_line, // 4 线状 + ERROR_TYPE_zangwu, // 5 脏污 + ERROR_TYPE_edge, // 6 边缘 + ERROR_TYPE_ymhs, // 7 研磨划伤 + ERROR_TYPE_dianzhuang, // 8 点状 + ERROR_TYPE_posun, // 9 破损 + ERROR_TYPE_xianwei, // 10 纤维 + ERROR_TYPE_shuizi, // 11 水渍 + ERROR_TYPE_danban, // 12 淡斑 + ERROR_TYPE_fuchen, // 13 浮尘 + ERROR_TYPE_COUNT, +}; +extern std::vector QX_Result_Names; +extern std::vector QX_Result_Code; +// 检测检测参数类型 +enum CHECK_CONFIG_TYPE_ +{ + CHECK_CONFIG_Run, // 运行参数 + CHECK_CONFIG_Module, // 参数模块 + CHECK_CONFIG_COUNT, +}; +// 输入检测图片的 +enum IMG_INPUT_ +{ + IMG_INPUT_SRC, + IMG_INPUT_COUNT, +}; +// 输入检测缺陷小图 +enum IMG_OUTPUT_ +{ + IMG_OUTPUT_RESIZE, + IMG_OUTPUT_COUNT, +}; +// 输入图片的状态 +enum IN_IMG_Status_ +{ + IN_IMG_Status_Start, + IN_IMG_Status_Other, + IN_IMG_Status_End, + IN_IMG_Status_OneImg, +}; +// 检测模式 +enum DET_MODE_ +{ + DET_MODE_NULL, + DET_MODE_EDGE, + DET_MODE_MergeImg, + DET_MODE_YX, + DET_MODE_UP, + DET_MODE_Det, + DET_MODE_MarkLine, + DET_MODE_ReJson, +}; + +#define MAX_REGION_NUM 20 +struct ReadFlawCode +{ + std::string flaw_name; + std::string flaw_code; + std::vector config_flaw_name; + ReadFlawCode() + { + config_flaw_name.clear(); + flaw_name = ""; + flaw_code = ""; + } +}; +extern std::vector m_FlawCodeList; + +// 一个检测项基本信息,包括图片序号,图片、开始时间 +struct shareImage +{ + int Det_Mode; // 检测模式 + int Status; + bool bCam_AB; // 是AB两个相机 + int camera_ID; // 相机ID + int img_id; + cv::Mat img; + cv::Mat img_B; + cv::Mat other_channel_Result_mask; + cv::Mat AI_maskImg; // 推理图片 + std::string strSnowID; // 相机发古来的雪花码 + long getImgTimeMs; // 获取图片的时间点 + long readImg_start; + long readImg_end; + long time_PushIn; + long time_sendCheck; + long time_startCheck; + long time_EndCheck; + int imgtype; + cv::Rect cutRoi; + + int ninstruct; // 运行指令 + int nlogLevel; // 日志等级 + + std::string strCameraName; // 相机名称 + std::string strImgProductID; // 产品名称 + std::string strChannel; // 通道名称 + std::string strImgName; // 图片名称 + std::string imgstr; + + int nImgBigIdx; + int otherValue; + int otherValue_1; + std::string resultJson; // 检测结果 json 字符串 + bool bsaveProcessImg; // 保存处理图片 + + std::unordered_map runCommand; // 运行命令 map + shareImage() + { + Init(); + } + ~shareImage() + { + } + void Init() + { + if (!img.empty()) + { + img.release(); + } + if (!other_channel_Result_mask.empty()) + { + other_channel_Result_mask.release(); + } + if (!AI_maskImg.empty()) + { + AI_maskImg.release(); + } + Det_Mode = 0; + Status = 0; + nlogLevel = DET_LOG_LEVEL_0; + img_id = -1; + getImgTimeMs = 0; + time_PushIn = 0; + time_sendCheck = 0; + time_startCheck = 0; + time_EndCheck = 0; + readImg_start = 0; + readImg_end = 0; + imgtype = 0; + imgstr = ""; + strSnowID = ""; + camera_ID = 0; + bCam_AB = false; + strImgName = ""; + strCameraName = ""; + strImgProductID = ""; + strChannel = ""; + nImgBigIdx = 0; + cutRoi = cv::Rect(0, 0, 0, 0); + otherValue = 0; + ninstruct = 0; + resultJson = ""; + bsaveProcessImg = false; + } + void InitImg(int ImgW, int imgH, bool Isgray = true) + { + if (Isgray) + { + img = cv::Mat(imgH, ImgW, CV_8UC1); + } + else + { + img = cv::Mat(imgH, ImgW, CV_8UC3); + } + } +}; + +// 检测结果基本信息 +struct BasicResult +{ + int img_id; + long checkUseTimeMs; // 所有时间 + int64_t snowId; // 雪花ID + int imgtype; + std::string imgstr; + std::string strChannel; + void Init() + { + img_id = 0; + checkUseTimeMs = 0; + snowId = 0; + imgtype = 0; + imgstr = ""; + strChannel = ""; + } + void copy(BasicResult tem) + { + this->img_id = tem.img_id; + this->checkUseTimeMs = tem.checkUseTimeMs; + this->snowId = tem.snowId; + this->imgtype = tem.imgtype; + this->imgstr = tem.imgstr; + this->strChannel = tem.strChannel; + } +}; + +struct DetectInfo +{ + int nresult; + std::string keyName; + std::string keyCode; + int num; + DetectInfo() + { + Init(); + } + void Init() + { + nresult = 0; + num = 0; + keyName = ""; + keyCode = ""; + } + void copy(DetectInfo tem) + { + this->nresult = tem.nresult; + this->num = tem.num; + this->keyName = tem.keyName; + this->keyCode = tem.keyCode; + } +}; + +struct QXImageResult +{ + int type; // 缺陷类型 + std::string qx_Code; // 缺陷code + std::string strTypeName; // 缺陷名称 + + cv::Mat srcImg; // 缺陷原始图片 + cv::Mat resizeImg; // 缺陷缩略图 + cv::Mat AI_in_Img; + cv::Mat AI_out_img; + + cv::Rect srcImgroi; // 相对原图的 框坐标; + cv::Rect CutImgroi; // 裁剪原图 框坐标; + cv::Rect resizeImgroi; // 相对相对小图 框坐标; + + float x_pixel; // 缺陷坐标 像素 + float y_pixel; // 缺陷坐标 像素 + + float x_mm; // 缺陷坐标 mm + float y_mm; // 缺陷坐标 mm + int idx; + float area; + float energy; + float hj; + float max_v; + float len; + float breadth; + float fScore; + int qx_type; // 缺陷的原因 + float minDis_mm; + int qx_num; + float density; // 密度 + + QXImageResult() + { + Init(); + } + void Init() + { + if (!srcImg.empty()) + { + srcImg.release(); + } + if (!resizeImg.empty()) + { + resizeImg.release(); + } + if (!AI_in_Img.empty()) + { + AI_in_Img.release(); + /* code */ + } + if (!AI_out_img.empty()) + { + AI_out_img.release(); + /* code */ + } + + x_pixel = 0; + y_pixel = 0; + x_mm = 0; + y_mm = 0; + type = 0; + area = 0; + energy = 0; + hj = 0; + max_v = 0; + strTypeName = ""; + qx_Code = ""; + len = 0; + breadth = 0; + idx = 0; + fScore = 0; + qx_type = 0; + minDis_mm = 0; + qx_num = 0; + density = 0; + srcImgroi = cv::Rect(0, 0, 0, 0); + CutImgroi = cv::Rect(0, 0, 0, 0); + resizeImgroi = cv::Rect(0, 0, 0, 0); + } +}; +// 结果信息 +struct CheckResult +{ + // 原始图片,输入检测的图片 + int checkStatus; + int nDetStep; // 处理步骤 + int nresult; + int nProductResult; // 产品结果 + int nYS_result; + float productWidht_mm; // 产品宽度 毫米 + float productHeight_mm; // 产品 高度 毫米 + cv::Mat cutSrcimg; + cv::Mat resultimg; + cv::Mat SrcResultImg; // 结果 + cv::Mat resultMaskImg; // AI mask Result + std::shared_ptr in_shareImage; // 输入图片信息 + DetectInfo defectResultList[ERROR_TYPE_COUNT]; // 缺陷检测结果list + BasicResult basicResult; // 基本检测结果信息 + std::vector qxImageResult; // 缺陷小图结果 + std::vector YS_ImageResult; // 疑似小图结果 + std::vector det_LogList; // 检测日志 + std::string strResultJson; // 缺陷结果 jason + bool bSaveALL; + int nflage1; + int nflage2; + CheckResult() + { + Init(); + } + ~CheckResult() + { + release(); + } + void Init() + { + nProductResult = 0; + checkStatus = 0; + nDetStep = 0; + nresult = ERROR_TYPE_OK; + nYS_result = ERROR_TYPE_OK; + bSaveALL = false; + nflage1 = 0; + nflage2 = 0; + productWidht_mm = 0; + productHeight_mm = 0; + basicResult.Init(); + strResultJson = ""; + if (!resultimg.empty()) + { + resultimg.release(); + } + if (!cutSrcimg.empty()) + { + cutSrcimg.release(); + } + if (!SrcResultImg.empty()) + { + SrcResultImg.release(); + } + if (!resultMaskImg.empty()) + { + resultMaskImg.release(); + } + for (int i = 0; i < ERROR_TYPE_COUNT; i++) + { + defectResultList[i].Init(); + } + std::vector tmp; + qxImageResult.swap(tmp); + YS_ImageResult.swap(tmp); + qxImageResult.erase(qxImageResult.begin(), qxImageResult.end()); + YS_ImageResult.erase(YS_ImageResult.begin(), YS_ImageResult.end()); + det_LogList.erase(det_LogList.begin(), det_LogList.end()); + } + + void release() + { + if (!resultimg.empty()) + { + resultimg.release(); + } + if (!cutSrcimg.empty()) + { + cutSrcimg.release(); + } + if (!SrcResultImg.empty()) + { + SrcResultImg.release(); + } + if (!resultMaskImg.empty()) + { + resultMaskImg.release(); + } + strResultJson = ""; + std::vector tmp; + qxImageResult.swap(tmp); + YS_ImageResult.swap(tmp); + det_LogList.erase(det_LogList.begin(), det_LogList.end()); + } +}; + +#endif //_CORELOGICFACTORY_HPP_ \ No newline at end of file diff --git a/AlgorithmModule/include/OtherDetBaseDefine.h b/AlgorithmModule/include/OtherDetBaseDefine.h new file mode 100644 index 0000000..93c0175 --- /dev/null +++ b/AlgorithmModule/include/OtherDetBaseDefine.h @@ -0,0 +1,36 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:49:50 + * @LastEditTime: 2025-09-17 18:57:39 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/include/CamDeal.h + */ +#ifndef OtherDetBaseDefine_H_ +#define OtherDetBaseDefine_H_ +#include +#include +#include "CheckErrorCodeDefine.hpp" +#include "BlobBase.h" + +using namespace std; + +struct OtherDet_Config +{ + int nDeviceId; // GPU 号 + int nUserValue; + int nShowImg_Width; + int nShowImg_Height; + + OtherDet_Config() + { + + + nDeviceId = 0; + nUserValue = 0; + nShowImg_Width = 100; + nShowImg_Height = 100; + } +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/OtherDetect.h b/AlgorithmModule/include/OtherDetect.h new file mode 100644 index 0000000..1668730 --- /dev/null +++ b/AlgorithmModule/include/OtherDetect.h @@ -0,0 +1,73 @@ +/* +//其他类的检测 + */ +#ifndef OtherDetect_H_ +#define OtherDetect_H_ +#include +#include "CheckUtil.hpp" +#include "OtherDetBaseDefine.h" +#include "CheckErrorCodeDefine.hpp" + +using namespace std; +using namespace cv; +// 基础类 +class AIDetectBase +{ + +public: + AIDetectBase(/* args */); + ~AIDetectBase(); + int Init(OtherDet_Config *pOtherDet_Config); + +protected: + OtherDet_Config *m_pOtherDet_Config; + + bool m_bInitialized; + bool m_bModelSucc; +}; + +// 缺pol 检测 +class LackPolDet : public AIDetectBase +{ + +public: + /// @brief 检测过程的参数 + struct DetConfig + { + float fImgage_Scale_X; + float fImgage_Scale_Y; + bool bSaveResultImg; // 保存结果图片 + std::string strChannel; // 通道名称 + cv::Mat detMaskImg; // 检测区域图片 + DetConfig() + { + Init(); + } + void Init() + { + fImgage_Scale_X = 0.03f; + fImgage_Scale_Y = 0.03f; + bSaveResultImg = false; + strChannel = ""; + } + void Print() + { + printf("bSaveResultImg %s strChannel %s\n", + BOOL_TO_STR(bSaveResultImg), strChannel.c_str()); + } + }; + +public: + LackPolDet(/* args */); + ~LackPolDet(); + int InitModel_ALL(); + int Detect(const cv::Mat &img, DetConfig *pDetConfig, cv::Mat &outMask); + +private: + int Init_LackPol(); + +public: +private: +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/Product.h b/AlgorithmModule/include/Product.h new file mode 100644 index 0000000..29f8134 --- /dev/null +++ b/AlgorithmModule/include/Product.h @@ -0,0 +1,67 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:49:50 + * @LastEditTime: 2025-09-16 21:19:45 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/include/CamDeal.h + */ +#ifndef Product_H_ +#define Product_H_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Define_Product.hpp" +#include "CameraResult.h" +#include "CheckErrorCodeDefine.hpp" +#include "ImageDetConfig.h" +using namespace std; +using namespace cv; + +class Product +{ +private: + /* data */ +public: + Product(/* args */); + ~Product(); + + std::shared_ptr GetCameraResult(std::string strcameraName); + void AddLog(std::string str); + // 更新 送图状态 + void UpdatePushStatus(int status); + + // 是否全部检测完成 + bool bCheckCamplate(); + void SetCheckEnd(); + +public: + // 相机结果 + std::vector> m_pCameraResultList; + std::shared_ptr productBaseResult; + // 图片是否都送完了。 + bool bIsImgComplete = false; + // 日志 + std::vector LogList; + std::mutex mtx_CameraResultList; + + +private: + std::mutex mtx_; + // 多线程安全 + + PRINT_LOG_ m_PrintLog; + std::string strEndTime; + long time_pushImg_end; + long time_CheckImg_end; + long product_UseAllTime; +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/Task.h b/AlgorithmModule/include/Task.h new file mode 100644 index 0000000..6ee1f83 --- /dev/null +++ b/AlgorithmModule/include/Task.h @@ -0,0 +1,96 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:49:50 + * @LastEditTime: 2025-09-16 10:14:05 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/include/CamDeal.h + */ +#ifndef Task_H_ +#define Task_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum TaskName +{ + Task_AI, + Task_Class, + Task_Count, +}; +enum TaskStep +{ + TaskStep_Idle, + TaskStep_Waite, + TaskStep_run, + TaskStep_compate, +}; +struct TaskInfo +{ + TaskName taskname; + TaskStep status; // 运行状态 + int nresult; // 运行结果 + + // 🔑 新增变量 + std::mutex mtx; + std::condition_variable cv; + + // 设置状态,线程安全 + void SetStatus(TaskStep newStatus) + { + { + std::lock_guard lock(mtx); + status = newStatus; + } + cv.notify_all(); // 通知等待者 + } + bool isComplate() + { + bool bcom = false; + { + std::lock_guard lock(mtx); + if (status == TaskStep_compate) + { + bcom = true; + } + } + + return bcom; + } + // 等待任务完成 + void waitComplate() + { + std::unique_lock lock(mtx); + cv.wait(lock, [this] + { return status == TaskStep_compate; }); + } +}; +using namespace std; + +class Task +{ +public: + Task(); + ~Task(); + int sendTask(std::shared_ptr task); + std::shared_ptr GetTask(); + +private: + std::queue> m_tasks_; + std::mutex m_task_mutex_; + std::condition_variable m_task_cv_; + +private: +public: +private: +private: +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/include/snowflake.hpp b/AlgorithmModule/include/snowflake.hpp new file mode 100644 index 0000000..9ea6a04 --- /dev/null +++ b/AlgorithmModule/include/snowflake.hpp @@ -0,0 +1,106 @@ +#pragma once +#include +#include +#include +#include + +class snowflake_nonlock +{ +public: + void lock() + { + } + void unlock() + { + } +}; + +template +class snowflake +{ + using lock_type = Lock; + static constexpr int64_t TWEPOCH = Twepoch; + static constexpr int64_t WORKER_ID_BITS = 5L; + static constexpr int64_t DATACENTER_ID_BITS = 5L; + static constexpr int64_t MAX_WORKER_ID = (1 << WORKER_ID_BITS) - 1; + static constexpr int64_t MAX_DATACENTER_ID = (1 << DATACENTER_ID_BITS) - 1; + static constexpr int64_t SEQUENCE_BITS = 12L; + static constexpr int64_t WORKER_ID_SHIFT = SEQUENCE_BITS; + static constexpr int64_t DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS; + static constexpr int64_t TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS; + static constexpr int64_t SEQUENCE_MASK = (1 << SEQUENCE_BITS) - 1; + + using time_point = std::chrono::time_point; + + time_point start_time_point_ = std::chrono::steady_clock::now(); + int64_t start_millsecond_ = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + + int64_t last_timestamp_ = -1; + int64_t workerid_ = 0; + int64_t datacenterid_ = 0; + int64_t sequence_ = 0; + lock_type lock_; +public: + snowflake() = default; + + snowflake(const snowflake&) = delete; + + snowflake& operator=(const snowflake&) = delete; + + void init(int64_t workerid, int64_t datacenterid) + { + if (workerid > MAX_WORKER_ID || workerid < 0) { + throw std::runtime_error("worker Id can't be greater than 31 or less than 0"); + } + + if (datacenterid > MAX_DATACENTER_ID || datacenterid < 0) { + throw std::runtime_error("datacenter Id can't be greater than 31 or less than 0"); + } + + workerid_ = workerid; + datacenterid_ = datacenterid; + } + + int64_t nextid() + { + std::lock_guard lock(lock_); + //std::chrono::steady_clock cannot decrease as physical time moves forward + auto timestamp = millsecond(); + if (last_timestamp_ == timestamp) + { + sequence_ = (sequence_ + 1)&SEQUENCE_MASK; + if (sequence_ == 0) + { + timestamp = wait_next_millis(last_timestamp_); + } + } + else + { + sequence_ = 0; + } + + last_timestamp_ = timestamp; + + return ((timestamp - TWEPOCH) << TIMESTAMP_LEFT_SHIFT) + | (datacenterid_ << DATACENTER_ID_SHIFT) + | (workerid_ << WORKER_ID_SHIFT) + | sequence_; + } + +private: + int64_t millsecond() const noexcept + { + auto diff = std::chrono::duration_cast(std::chrono::steady_clock::now() - start_time_point_); + return start_millsecond_ + diff.count(); + } + + int64_t wait_next_millis(int64_t last) const noexcept + { + auto timestamp = millsecond(); + while (timestamp <= last) + { + timestamp = millsecond(); + } + return timestamp; + } +}; diff --git a/AlgorithmModule/src/AI_Edge_Algin.cpp b/AlgorithmModule/src/AI_Edge_Algin.cpp new file mode 100644 index 0000000..975d399 --- /dev/null +++ b/AlgorithmModule/src/AI_Edge_Algin.cpp @@ -0,0 +1,1064 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-09-11 15:32:52 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-22 16:56:41 + * @FilePath: /BOE_CELL_AOI_Detect/AlgorithmModule/src/AI_Edge_Algin.cpp + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ + +#include "AI_Edge_Algin.h" +#include "CheckErrorCodeDefine.hpp" + +#define EDGE_GPU 0 + +#include // OpenCV核心功能 +#include // 图像处理模块 +#include // 向量容器 +#include // 输入输出流 + +/** + * @class SimilarityTransform + * @brief 用于计算和存储相似变换(旋转、缩放、平移) + * + * 通过两个点对计算模板图像到检测图像的相似变换 + */ +class SimilarityTransform +{ +public: + /** + * @brief 构造函数,使用两个点对初始化变换矩阵 + * + * @param template_p1 模板点1 + * @param template_p2 模板点2 + * @param detected_d1 检测点1 + * @param detected_d2 检测点2 + */ + SimilarityTransform(const cv::Point2f &template_p1, + const cv::Point2f &template_p2, + const cv::Point2f &detected_d1, + const cv::Point2f &detected_d2) + { + std::vector template_pts = {template_p1, template_p2}; + std::vector detected_pts = {detected_d1, detected_d2}; + + // 计算相似变换矩阵 + transform_matrix_ = cv::estimateAffinePartial2D(template_pts, detected_pts); + + if (transform_matrix_.empty()) + { + valid_ = false; + std::cerr << "Error: Failed to calculate transformation matrix." << std::endl; + } + else + { + valid_ = true; + extractParameters(); + } + } + + /** + * @brief 检查变换矩阵是否有效 + * @return bool 变换是否有效 + */ + bool isValid() const { return valid_; } + + /** + * @brief 获取旋转角度(度) + * @return double 旋转角度(度) + */ + double getRotationAngle() const { return rotation_angle_; } + + /** + * @brief 获取缩放比例 + * @return double 缩放比例 + */ + double getScaleFactor() const { return scale_factor_; } + + /** + * @brief 获取平移分量 + * @return cv::Point2f 平移向量(tx, ty) + */ + cv::Point2f getTranslation() const + { + return cv::Point2f(transform_matrix_.at(0, 2), + transform_matrix_.at(1, 2)); + } + + /** + * @brief 转换点坐标 + * + * @param point 输入点(模板坐标系) + * @return cv::Point2f 转换后的点(检测图像坐标系) + */ + cv::Point2f transformPoint(const cv::Point2f &point) const + { + if (!valid_) + { + std::cerr << "Warning: Using invalid transform! Returning original point." << std::endl; + return point; + } + + // 使用矩阵乘法进行点变换 + cv::Mat point_mat = (cv::Mat_(3, 1) << point.x, point.y, 1); + cv::Mat result_mat = transform_matrix_ * point_mat; + + return cv::Point2f(result_mat.at(0), result_mat.at(1)); + } + + /** + * @brief 批量转换点坐标 + * + * @param points 输入点集(模板坐标系) + * @return std::vector 转换后的点集(检测图像坐标系) + */ + std::vector transformPoints(const std::vector &points) const + { + if (!valid_) + { + std::cerr << "Warning: Using invalid transform! Returning original points." << std::endl; + return points; + } + + std::vector result; + cv::transform(points, result, transform_matrix_); + return result; + } + + /** + * @brief 获取变换矩阵 + * @return cv::Mat 2x3变换矩阵 + */ + cv::Mat getTransformMatrix() const { return transform_matrix_; } + +private: + /** + * @brief 从变换矩阵中提取旋转角度和缩放比例 + */ + void extractParameters() + { + double a = transform_matrix_.at(0, 0); + double b = transform_matrix_.at(0, 1); + + // 计算旋转角度(弧度转角度) + rotation_angle_ = std::atan2(b, a) * 180.0 / CV_PI; + + // 计算缩放比例 + scale_factor_ = std::sqrt(a * a + b * b); + } + + cv::Mat transform_matrix_; // 2x3 变换矩阵 + bool valid_ = false; // 变换是否有效 + double rotation_angle_ = 0; // 旋转角度(度) + double scale_factor_ = 1; // 缩放比例 +}; + +/** + * @brief 独立转换函数(使用变换矩阵) + * + * @param point 输入点(模板坐标系) + * @param transform_matrix 2x3变换矩阵 + * @return cv::Point2f 转换后的点(检测图像坐标系) + */ +cv::Point2f transformPoint(const cv::Point2f &point, const cv::Mat &transform_matrix) +{ + // 验证变换矩阵有效性 + if (transform_matrix.empty() || transform_matrix.rows != 2 || transform_matrix.cols != 3) + { + std::cerr << "Error: Invalid transformation matrix! Returning original point." << std::endl; + return point; + } + + // 使用矩阵乘法进行点变换 + cv::Mat point_mat = (cv::Mat_(3, 1) << point.x, point.y, 1); + cv::Mat result_mat = transform_matrix * point_mat; + + return cv::Point2f(result_mat.at(0), result_mat.at(1)); +} + +AI_Edge_Algin::AI_Edge_Algin(std::shared_ptr &log_ref) + : m_pdetlog(log_ref) +{ + m_bInitialized = false; + m_bModelSucc = false; + m_bModel_Mark_Succ = false; + m_bshowimg = false; + m_strRootPath_Big = "/home/aidlux/BOE/Algin/"; + m_strRootPath_Mark = "/home/aidlux/BOE/MarkLine/"; + creatsavedir(); + std::string m_strSavePath; + + m_pImageStorage = ImageStorage::getInstance(); +} + +AI_Edge_Algin::~AI_Edge_Algin() +{ +} + +int AI_Edge_Algin::Init(OtherDet_Config *pOtherDet_Config) +{ + m_pOtherDet_Config = pOtherDet_Config; + + AI_Factory = AIFactory::GetInstance(); + + m_bInitialized = true; + return 0; +} +int AI_Edge_Algin::Detect(const cv::Mat &img, DetConfig *pDetConfig, std::shared_ptr &pCheckResult_Aling) +{ + m_pCheckResult_Aling = std::make_shared(); + pCheckResult_Aling = m_pCheckResult_Aling; + m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "start"); + + m_pDetConfig = pDetConfig; + static int erridx = 0; + std::string str_error = ""; + + // 保存过程图片 + if (m_pDetConfig->IsSaveProcessImg()) + { + erridx++; + if (erridx > 9999999) + { + erridx = 0; + } + str_error = "/home/aidlux/BOE/Edge/Error/" + std::to_string(erridx) + "_src.png"; + } + + if (img.empty()) + { + return 1; + } + + // 1、初步定位 找到产品大致区域 + int re = 0; + + cv::Rect Big_roi; + + re = Det_big(img, pDetConfig, m_pDetConfig->strChannel, Big_roi); + if (re != 0) + { + m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "AICheck_Edge_Big----error %d ", re); + if (m_pDetConfig->IsSaveProcessImg()) + { + cv::imwrite(str_error, img); + } + return re; + } + m_pCheckResult_Aling->roi = Big_roi; + + re = MarkAlign(img, pDetConfig, Big_roi); + + pCheckResult_Aling = m_pCheckResult_Aling; + // return 1; + + return 0; +} + +int AI_Edge_Algin::SaveSmallImg(const cv::Mat &img, const cv::Mat &mask, cv::Rect roi) +{ + // 是否要保存中间过程的小图 + if (m_pDetConfig->IsSaveProcessImg()) + { + static int svsmallidx = 0; + svsmallidx++; + if (svsmallidx > 9999999) + { + svsmallidx = 0; + /* code */ + } + bool bssss = false; + + if (m_pDetConfig->saveProcessImg == Save_Filter) + { + // 4. 查找轮廓 + vector> contours; + vector hierarchy; + findContours(mask.clone(), contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); + if (contours.size() > 1) + { + bssss = true; + } + else if (contours.size() == 1) + { + int pointNum = 0; + for (int i = 0; i < contours.size(); i++) + { + pointNum += contours[i].size(); + } + // printf("pointNum============== %d\n", pointNum); + if (pointNum > 30) + { + bssss = true; + } + } + } + else if (m_pDetConfig->saveProcessImg == Save_ALL) + { + bssss = true; + } + + if (bssss) + { + std::string str1 = "/home/aidlux/BOE/Edge/Smasll/" + std::to_string(svsmallidx) + "_in.png"; + std::string str2 = "/home/aidlux/BOE/Edge/Smasll/" + std::to_string(svsmallidx) + "_in_mask.png"; + // std::string st3 = "/home/aidlux/BOE/Edge/Smasll/" + std::to_string(svsmallidx) + "_in_show.png"; + cv::imwrite(str1, img); + cv::imwrite(str2, mask); + // cv::Mat showsss = temDet + smask * 0.4; + // cv::imwrite(st3, showsss); + } + } + return 0; +} + +int AI_Edge_Algin::MarkAlign(const cv::Mat &img, DetConfig *pDetConfig, cv::Rect bigroi) +{ + m_bshowimg = false; + if (pDetConfig->bSaveResultImg) + { + m_bshowimg = true; + } + + // pDetConfig->pBaseCheckFunction->markLine.print("dfe"); + // if (!m_bModel_Mark_Succ) + // { + // m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "MarkAlign ", "error ---- model Init error"); + // return 0; + // } + + // 定位mark点,精确 定位 + if (!pDetConfig->pBaseCheckFunction->markLine.bOpen) + { + m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "MarkAlign ", "error ---- param is close"); + return 0; + } + if (img.empty()) + { + m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "MarkAlign ", "error ---- img.empty()"); + return -11; + } + // 检查roi; + if (!CheckUtil::RoiInImg(bigroi, img)) + { + m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "MarkAlign ", "error ---- roi [%d %d %d %d] img %d %d", + bigroi.x, bigroi.y, bigroi.width, bigroi.height, img.cols, img.rows); + return -13; + } + m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "MarkAlign ", "start"); + + if (m_bshowimg) + { + if (img.channels() != 1) + { + showimg = img.clone(); + } + else + { + cv::cvtColor(img, showimg, cv::COLOR_GRAY2BGR); + } + } + // 第一个mark点 处理 + if (pDetConfig->pBaseCheckFunction->markLine.mark_local_1.x > 0 && + pDetConfig->pBaseCheckFunction->markLine.mark_local_1.y > 0) + { + Det_MarkPoint(img, pDetConfig, bigroi, pDetConfig->pBaseCheckFunction->markLine.mark_local_1); + } + if (pDetConfig->pBaseCheckFunction->markLine.mark_local_2.x > 0 && + pDetConfig->pBaseCheckFunction->markLine.mark_local_2.y > 0) + { + Det_MarkPoint(img, pDetConfig, bigroi, pDetConfig->pBaseCheckFunction->markLine.mark_local_2); + } + AnalsysMarkPoint(img, pDetConfig); + // getchar(); + + // if (m_bshowimg) + // { + // if (pDetConfig->pBaseCheckFunction->markLine.mark_local_1.x > 0 && + // pDetConfig->pBaseCheckFunction->markLine.mark_local_1.y > 0) + // { + // cv::circle(showimg, pDetConfig->pBaseCheckFunction->markLine.mark_local_1, 5, cv::Scalar(255, 255, 0)); + // } + // if (pDetConfig->pBaseCheckFunction->markLine.mark_local_2.x > 0 && + // pDetConfig->pBaseCheckFunction->markLine.mark_local_2.y > 0) + // { + // cv::circle(showimg, pDetConfig->pBaseCheckFunction->markLine.mark_local_2, 5, cv::Scalar(255, 255, 0)); + // } + + // cv::imwrite(pDetConfig->strChannel + "mark_show.png", showimg); + // } + + // getchar(); + + return 0; +} + +int AI_Edge_Algin::InitModel_ALL() +{ + + m_bModelSucc = true; + return 0; +} + +int AI_Edge_Algin::Det_big(const cv::Mat &img, DetConfig *pDetConfig, std::string strChannel, cv::Rect &bigRoi) +{ + std::shared_ptr pCELL_Align = AI_Factory->CELL_Align; + cv::Size sz; + sz.width = pCELL_Align->input_0.width; + sz.height = pCELL_Align->input_0.height; + cv::Mat detImg; + cout<< pDetConfig->strChannel << ": " << "---Det_big-resize--- "; + cout << "imgSize: " << img.size() << ", " << "detImgSize: " << detImg.size() << ", " << "szSize: " << sz << endl; + + cv::resize(img, detImg, sz); + int re = 0; + cv::Mat mask; + if (detImg.channels() != 1) + { + cv::cvtColor(detImg, detImg, cv::COLOR_RGB2GRAY); + } + + re = pCELL_Align->AIDet(detImg, mask); + if (re != 0) + { + m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "AICheck_Edge_Big----error %d ", re); + int re123 = 100 + re; + return re123; + } + + if (pDetConfig->pBaseCheckFunction->saveImg.bSaveAlginImg) + { + creatsavedir(); + static int sdk = 0; + std::string str = m_strSavePath_Big + std::to_string(sdk) + "_" + pDetConfig->strChannel + "_Img.png"; + int sr = m_pImageStorage->addImage(str, detImg); + if (sr == 0) + { + str = m_strSavePath_Big + std::to_string(sdk) + "_" + pDetConfig->strChannel + "_Img_mask.png"; + int sr = m_pImageStorage->addImage(str, mask, true); + sdk++; + if (sdk > 99999) + { + sdk = 0; + /* code */ + } + } + + // cv::imwrite(pDetConfig->strChannel +"_Mark_AI_DetImg.png", AI_DetImg); + // cv::imwrite(pDetConfig->strChannel + "_Mark_AI_DetImg_mask.png", outmask); + } + + if (m_pDetConfig->bSaveResultImg) + { + cv::imwrite(strChannel + "_edge_big_in.png", detImg); + cv::imwrite(strChannel + "_edge_big_out_mask.png", mask); + } + // getchar(); + // if (m_pDetConfig->IsSaveProcessImg()) + // { + // static int bigidx = 0; + // bigidx++; + // if (bigidx > 9999999) + // { + // bigidx = 0; + // /* code */ + // } + // std::string str1 = "/home/aidlux/BOE/Edge/Big/" + std::to_string(bigidx) + "_in.png"; + // std::string str2 = "/home/aidlux/BOE/Edge/Big/" + std::to_string(bigidx) + "_in_mask.png"; + // cv::imwrite(str1, detImg); + // cv::imwrite(str2, mask); + // } + + // 找到最大轮廓 + + bool found; + cv::Rect boundingBox = CheckUtil::getLargestContourROI(mask, found); + if (!found) + { + m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "No contours found!----error "); + return 4; + } + + // 形成 小图分割的检测区域 + float fresize_x = img.cols * 1.0f / sz.width; + float fresize_y = img.rows * 1.0f / sz.height; + + bigRoi.x = boundingBox.x * fresize_x; + bigRoi.y = boundingBox.y * fresize_y; + bigRoi.width = boundingBox.width * fresize_x; + bigRoi.height = boundingBox.height * fresize_y; + // std::cout << "AI edge succ" << endl; + return 0; +} + +int AI_Edge_Algin::Det_MarkPoint(const cv::Mat &img, DetConfig *pDetConfig, cv::Rect bigroi, cv::Point SampleImg_Local) +{ + std::shared_ptr pCELL_Mark = AI_Factory->CELL_Mark; + MarK_Result result; + // 根据 bigroi 把bigroi 映射到当前图片来。 + cv::Point CurImg_M_Local = cv::Point(0, 0); + cv::Point CurImg_Det_Local = cv::Point(0, 0); + + cv::Point basePoint = cv::Point(bigroi.x, bigroi.y); + + cv::Rect Productroi = pDetConfig->pBaseCheckFunction->markLine.productROI; + if (Productroi.width <= 0 || Productroi.height <= 0) + { + m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "MarkAlign ", "error ---Productroi.width <= 0 || Productroi.height <= 0 "); + return 0; + } + float fsize_x = bigroi.width * 1.0f / Productroi.width; + float fsize_y = bigroi.height * 1.0f / Productroi.height; + + m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "MarkAlign ", "mark 1 start"); + // 以左上为基准点 + if (bigroi.x > 0 && bigroi.y > 0) + { + basePoint = cv::Point(bigroi.x, bigroi.y); + + cv::Point Product_lu = cv::Point(Productroi.x, Productroi.y); + cv::Point cur_lu = cv::Point(bigroi.x, bigroi.y); + + CurImg_M_Local.x = cur_lu.x + (SampleImg_Local.x - Product_lu.x) * fsize_x + 40; + CurImg_M_Local.y = cur_lu.y + (SampleImg_Local.y - Product_lu.y) * fsize_y + 40; + } + else // 以右下为基准点 + { + basePoint = cv::Point(bigroi.x + bigroi.width, bigroi.y + bigroi.height); + + cv::Point Product_rl = cv::Point(Productroi.x + Productroi.width, Productroi.y + Productroi.height); + cv::Point cur_rl = cv::Point(bigroi.x + bigroi.width, bigroi.y + bigroi.height); + + CurImg_M_Local.x = cur_rl.x - (Product_rl.x - SampleImg_Local.x) * fsize_x - 40; + CurImg_M_Local.y = cur_rl.y - (Product_rl.y - SampleImg_Local.y) * fsize_y - 40; + } + + int AI_Img_width = 640; + int AI_Img_height = 640; + + cv::Rect AI_roi; + AI_roi.x = CurImg_M_Local.x - AI_Img_width * 0.5; + AI_roi.y = CurImg_M_Local.y - AI_Img_height * 0.5; + AI_roi.width = AI_Img_width; + AI_roi.height = AI_Img_height; + + if (AI_roi.x < bigroi.x) + { + AI_roi.x = bigroi.x; + } + if (AI_roi.y < bigroi.y) + { + AI_roi.y = bigroi.y; + } + if (AI_roi.x + AI_roi.width > (bigroi.x + bigroi.width)) + { + AI_roi.x = (bigroi.x + bigroi.width) - AI_roi.width; + } + if (AI_roi.y + AI_roi.height > (bigroi.y + bigroi.height)) + { + AI_roi.y = (bigroi.y + bigroi.height) - AI_roi.height; + } + + if (!CheckUtil::RoiInImg(AI_roi, img)) + { + m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "MarkAlign ", "error ---- AI_roi [%d %d %d %d] img %d %d", + AI_roi.x, AI_roi.y, AI_roi.width, AI_roi.height, img.cols, img.rows); + return 1; + } + + result.SearchROI_SrcImg = AI_roi; + result.param_Local_SrcImg = SampleImg_Local; + cv::Mat AI_DetImg; + if (img.channels() == 1) + { + AI_DetImg = img(AI_roi).clone(); + } + else + { + cv::cvtColor(img(AI_roi), AI_DetImg, cv::COLOR_BGR2GRAY); + } + cv::Mat outmask; + cv::Size sz; + sz.width = pCELL_Mark->input_0.width; + sz.height = pCELL_Mark->input_0.height; + cv::Mat AI_SizeImg; + cv::resize(AI_DetImg, AI_SizeImg, sz); + + int re = pCELL_Mark->AIDet(AI_SizeImg, outmask); + + if (outmask.empty()) + { + m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Mark_Det ", "AI Error,outmask.empty()"); + return 1; + } + // outmask *= 255; + if (pDetConfig->pBaseCheckFunction->saveImg.bSaveMarkImg) + { + creatsavedir(); + static int sdk = 0; + std::string str = m_strSavePath_Mark + std::to_string(sdk) + "_" + pDetConfig->strChannel + "_Img.png"; + int sr = m_pImageStorage->addImage(str, AI_DetImg); + if (sr == 0) + { + str = m_strSavePath_Mark + std::to_string(sdk) + "_" + pDetConfig->strChannel + "_Img_mask.png"; + int sr = m_pImageStorage->addImage(str, outmask, true); + sdk++; + if (sdk > 99999) + { + sdk = 0; + /* code */ + } + } + + // cv::imwrite(pDetConfig->strChannel +"_Mark_AI_DetImg.png", AI_DetImg); + // cv::imwrite(pDetConfig->strChannel + "_Mark_AI_DetImg_mask.png", outmask); + } + + bool bf = false; + cv::Rect markroi = CheckUtil::getLargestContourROI(outmask, bf); + + if (bf) + { + + CurImg_Det_Local.x = (markroi.x + markroi.width * 0.5) * 2 + AI_roi.x; + CurImg_Det_Local.y = (markroi.y + markroi.height * 0.5) * 2 + AI_roi.y; + result.det_Local_SrcImg = CurImg_Det_Local; + } + + if (m_bshowimg) + { + cv::circle(showimg, basePoint, 10, cv::Scalar(0, 255, 0), -1); + + cv::circle(showimg, CurImg_M_Local, 10, cv::Scalar(255, 255, 0), -1); + cv::circle(showimg, CurImg_Det_Local, 10, cv::Scalar(0, 0, 255), 3); + + cv::circle(showimg, SampleImg_Local, 10, cv::Scalar(255, 0, 255)); + + cv::rectangle(showimg, AI_roi, cv::Scalar(255, 0, 0), 2); + + cv::rectangle(showimg, pDetConfig->pBaseCheckFunction->markLine.productROI, cv::Scalar(128, 0, 0)); + cv::imwrite(pDetConfig->strChannel + "mark_show111.tif", showimg); + } + if (bf) + { + } + else + { + m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Mark_Det ", " No find "); + return 1; + } + + m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Mark_Det ", " succ--------"); + result.status = Mark_Result_Status_OK; + m_pCheckResult_Aling->markresulList.push_back(result); + return 0; +} + +int AI_Edge_Algin::AnalsysMarkPoint(const cv::Mat &img, DetConfig *pDetConfig) +{ + Base_Function_MarkLine *pmarkLine = &pDetConfig->pBaseCheckFunction->markLine; + if (m_pCheckResult_Aling->markresulList.size() < 0) + { + return 1; + } + int sum_x = 0; + int sum_y = 0; + int num = 0; + for (const auto mark : m_pCheckResult_Aling->markresulList) + { + sum_x += mark.param_Local_SrcImg.x - mark.det_Local_SrcImg.x; + sum_y += mark.param_Local_SrcImg.y - mark.det_Local_SrcImg.y; + num++; + } + if (num <= 0) + { + return 1; + /* code */ + } + + int avg_x = -sum_x / num; + int avg_y = -sum_y / num; + m_pCheckResult_Aling->offt_x = avg_x; + m_pCheckResult_Aling->offt_y = avg_y; + m_pCheckResult_Aling->buseOfft = true; + + cv::Rect mroi = pmarkLine->productROI; + mroi.x += avg_x; + mroi.y += avg_y; + + if (mroi.x < 0) + { + mroi.width += mroi.x; + mroi.x = 0; + } + if (mroi.y < 0) + { + mroi.height += mroi.y; + mroi.y = 0; + } + if (mroi.x + mroi.width > img.cols) + { + mroi.width = img.cols - mroi.x; + } + if (mroi.y + mroi.height > img.rows) + { + mroi.height = img.rows - mroi.y; + } + + mroi = m_pCheckResult_Aling->roi ; + + if (!CheckUtil::RoiInImg(mroi, img)) + { + return 1; + } + + if (m_pCheckResult_Aling->markresulList.size() == 2) + { + cv::Point p1 = m_pCheckResult_Aling->markresulList[0].param_Local_SrcImg; + cv::Point p2 = m_pCheckResult_Aling->markresulList[1].param_Local_SrcImg; + + cv::Point d1 = m_pCheckResult_Aling->markresulList[0].det_Local_SrcImg; + cv::Point d2 = m_pCheckResult_Aling->markresulList[1].det_Local_SrcImg; + // 创建变换对象 + SimilarityTransform transform(p1, p2, d1, d2); + + cv::Mat matrix = transform.getTransformMatrix(); + m_pCheckResult_Aling->H = matrix.clone(); + } + + if (m_bshowimg) + { + std::vector srcdetregion; + for (size_t i = 0; i < pmarkLine->region.size(); ++i) + { + cv::Point2f mapped_point2 = transformPoint(pmarkLine->region[i], m_pCheckResult_Aling->H); + srcdetregion.push_back(mapped_point2); + } + + // 绘制产品边缘点 + for (size_t i = 0; i < pmarkLine->region.size(); ++i) + { + // 绘制每个点 + circle(showimg, pmarkLine->region[i], 5, Scalar(0, 0, 255), -1); + + // 连接每对相邻的点 + if (i < pmarkLine->region.size() - 1) + { + line(showimg, pmarkLine->region[i], pmarkLine->region[i + 1], Scalar(0, 255, 0), 2); + } + } + + // 如果点集合是闭合的(即最后一个点连接回第一个点) + if (pmarkLine->region.size() > 1) + { + line(showimg, pmarkLine->region[pmarkLine->region.size() - 1], pmarkLine->region[0], Scalar(0, 255, 0), 2); + } + + for (size_t i = 0; i < srcdetregion.size(); ++i) + { + // 绘制每个点 + circle(showimg, srcdetregion[i], 5, Scalar(255, 0, 255), -1); + + // 连接每对相邻的点 + if (i < srcdetregion.size() - 1) + { + line(showimg, srcdetregion[i], srcdetregion[i + 1], Scalar(255, 255, 0), 2); + } + } + + // 如果点集合是闭合的(即最后一个点连接回第一个点) + if (srcdetregion.size() > 1) + { + line(showimg, srcdetregion[srcdetregion.size() - 1], srcdetregion[0], Scalar(255, 0, 255), 2); + } + + for (size_t i = 0; i < m_pCheckResult_Aling->markresulList.size(); ++i) + { + circle(showimg, m_pCheckResult_Aling->markresulList[i].det_Local_SrcImg, 20, Scalar(255, 0, 0), 5); + } + cv::rectangle(showimg, m_pCheckResult_Aling->roi, cv::Scalar(0, 255, 255), 2); + + cv::rectangle(showimg, mroi, cv::Scalar(0, 255, 0), 2); + cv::rectangle(showimg, pDetConfig->pBaseCheckFunction->markLine.productROI, cv::Scalar(255, 0, 0), 2); + cv::imwrite(pDetConfig->strChannel + "mark_show.png", showimg); + } + + // CheckUtil::printROI(m_pCheckResult_Aling->roi, pDetConfig->strChannel + "big"); + // CheckUtil::printROI(mroi, pDetConfig->strChannel + "mroi"); + if (std::abs(m_pCheckResult_Aling->roi.x - mroi.x) < 1200 && + std::abs(m_pCheckResult_Aling->roi.y - mroi.y) < 1200 && + std::abs(m_pCheckResult_Aling->roi.width - mroi.width) < 1200 && + std::abs(m_pCheckResult_Aling->roi.height - mroi.height) < 1200) + { + + } + else + { + + m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Mark_Det ", " mark roi - big roi error "); + return 1; + } + + m_pCheckResult_Aling->roi = mroi; + + for (size_t i = 0; i < m_pCheckResult_Aling->markresulList.size(); ++i) + { + m_pCheckResult_Aling->markresulList[i].status = Mark_Result_Status_OK; + m_pCheckResult_Aling->markresulList[i].det_Local_DetImg.x = m_pCheckResult_Aling->markresulList[i].det_Local_SrcImg.x - mroi.x; + m_pCheckResult_Aling->markresulList[i].det_Local_DetImg.y = m_pCheckResult_Aling->markresulList[i].det_Local_SrcImg.y - mroi.y; + + m_pCheckResult_Aling->markresulList[i].param_Local_DetImg.x = m_pCheckResult_Aling->markresulList[i].param_Local_SrcImg.x - mroi.x; + m_pCheckResult_Aling->markresulList[i].param_Local_DetImg.y = m_pCheckResult_Aling->markresulList[i].param_Local_SrcImg.y - mroi.y; + } + + return 0; +} + +int AI_Edge_Algin::creatsavedir() +{ + std::string curDate = CheckUtil::getCurrentDate(); + if (curDate == m_strLastDate) + { + return 0; + } + m_strLastDate = curDate; + m_strSavePath_Big = m_strRootPath_Big + curDate + "/"; + m_strSavePath_Mark = m_strRootPath_Mark + curDate + "/"; + + CheckUtil::CreateDir(m_strSavePath_Big); + CheckUtil::CreateDir(m_strSavePath_Mark); + + return 0; + return 0; +} + +Image_Feature_Algin::Image_Feature_Algin() +{ +} + +Image_Feature_Algin::~Image_Feature_Algin() +{ +} + +int Image_Feature_Algin::Detect(DetConfig *pDetConfig, Align_Result *pResult, std::vector &LogList) +{ + // 检测目标:找到 参数模版图到 检测图的 映射关系。包括 缩放和移动。 + + // 先缩放 在 移动 + std::string strlog = ""; + if (!pDetConfig) + { + return 1; + } + if (pDetConfig->TemplateImg.empty()) + { + strlog = m_PrintLog.printstr(Print_Level_Error, "Image_Align", "TemplateImg is empty "); + LogList.push_back(strlog); + return 1; + } + // 裁切位置; + pResult->Crop_Roi_DetImg = pDetConfig->DetImg_CropROi; + // 1、缩放尺度 + float fx = 1; + float fy = 1; + // 裁切尺寸 存在 并合理 + if (pDetConfig->param_CropRoi.width > 0 && pDetConfig->param_CropRoi.height > 0 && + pDetConfig->DetImg_CropROi.width > 0 && pDetConfig->DetImg_CropROi.height > 0) + { + fx = pDetConfig->DetImg_CropROi.width * 1.0f / pDetConfig->param_CropRoi.width; + fy = pDetConfig->DetImg_CropROi.height * 1.0f / pDetConfig->param_CropRoi.height; + if (fx > 0.5 && fx < 2 && fy > 0.5 && fy < 2) + { + pResult->fCropROI_Scale_ParmToDet_X = fx; + pResult->fCropROI_Scale_ParmToDet_Y = fy; + } + else + { + strlog = m_PrintLog.printstr(Print_Level_Error, "Image_Align", "Scale out 0.5--2"); + LogList.push_back(strlog); + return 1; + } + } + else + { + strlog = m_PrintLog.printstr(Print_Level_Error, "Image_Align", "crop ROI Error"); + LogList.push_back(strlog); + return 1; + } + // strlog = m_PrintLog.printstr(Print_Level_Info, "Image_Align", "Scale x %f y %f\n", fx, fy); + // LogList.push_back(strlog); + + // 2、定位 + // 1)、模版特征图片的 缩放。 + cv::Mat TemplateFeature; + cv::Size sz; + // fx = 1; + // fy = 1; + sz.width = int(pDetConfig->TemplateImg.cols * fx); + sz.height = int(pDetConfig->TemplateImg.rows * fy); + cv::resize(pDetConfig->TemplateImg, TemplateFeature, sz); + + if (!CheckUtil::RoiInImg(pDetConfig->Search_Roi, pDetConfig->DetImg)) + { + strlog = m_PrintLog.printstr(Print_Level_Error, "Image_Align", "Search_Roi ROI Error Not In img"); + LogList.push_back(strlog); + return 1; + } + + cv::Mat DetFeature = pDetConfig->DetImg(pDetConfig->Search_Roi).clone(); + + double confidence = 0; + + int kernel_size = 128; + int search_size = 1024; + int det_search_min_size = DetFeature.cols; + if (DetFeature.rows < det_search_min_size) + { + det_search_min_size = DetFeature.rows; + } + int template_kernel_min_size = TemplateFeature.cols; + if (TemplateFeature.rows < template_kernel_min_size) + { + template_kernel_min_size = TemplateFeature.rows; + } + float f_search = search_size * 1.0f / det_search_min_size; + float f_Kernel = kernel_size * 1.0f / template_kernel_min_size; + float falign = f_search; + if (f_Kernel > falign) + { + falign = f_Kernel; + } + cv::Size Search_sz; + Search_sz.width = int(DetFeature.cols * falign); + Search_sz.height = int(DetFeature.rows * falign); + cv::Mat Search_img; + cv::resize(DetFeature, Search_img, Search_sz); + cv::Size Kernel_sz; + Kernel_sz.width = int(TemplateFeature.cols * falign); + Kernel_sz.height = int(TemplateFeature.rows * falign); + cv::Mat Kernel_img; + cv::resize(TemplateFeature, Kernel_img, Kernel_sz); + + auto bestMatch = findBestTemplateMatch(Search_img, Kernel_img, confidence); + + bestMatch.x /= falign; + bestMatch.y /= falign; + + pResult->bestMatch = bestMatch; + if (pDetConfig->bSaveImg) + { + cv::imwrite("Align_template.png", TemplateFeature); + cv::imwrite("Align_Det.png", DetFeature); + } + + if (confidence != -1) + { + std::cout << "最佳匹配位置: (" << bestMatch.x << ", " << bestMatch.y + << "), 得分: " << confidence << std::endl; + if (confidence > pDetConfig->fscore) + { + + /* code */ + + int m_x = pDetConfig->feature_Roi.x * fx - pDetConfig->Search_Roi.x; + int m_y = pDetConfig->feature_Roi.y * fy - pDetConfig->Search_Roi.y; + pResult->offt_x = bestMatch.x - m_x; + pResult->offt_y = bestMatch.y - m_y; + // printf("m_x %d bestMatch.x %d offt_x %d\n", m_x, bestMatch.x, pResult->offt_x); + // printf("m_y %d bestMatch.y %d offt_y %d\n", m_y, bestMatch.y, pResult->offt_y); + + pResult->bDet = true; + + pResult->Crop_Roi_ParmImg = pResult->Det_srcToParm_src_Rect(pResult->Crop_Roi_DetImg); + + strlog = m_PrintLog.printstr(Print_Level_Info, "Image_Align", " -- Succ :Align score %f > %f offt x %d y %d Scale x %f y %f", + confidence, pDetConfig->fscore, pResult->offt_x, pResult->offt_y, pResult->fCropROI_Scale_ParmToDet_X, pResult->fCropROI_Scale_ParmToDet_Y); + + LogList.push_back(strlog); + } + else + { + + strlog = m_PrintLog.printstr(Print_Level_Error, "Image_Align", " error :Align score %f< 0.9", confidence); + pResult->fCropROI_Scale_ParmToDet_X = 1; + pResult->fCropROI_Scale_ParmToDet_Y = 1; + LogList.push_back(strlog); + } + } + else + { + pResult->fCropROI_Scale_ParmToDet_X = 1; + pResult->fCropROI_Scale_ParmToDet_Y = 1; + std::cout << "未找到有效匹配" << std::endl; + } + + return 0; +} + +cv::Point Image_Feature_Algin::findBestTemplateMatch( + const cv::Mat &detectionImage, + const cv::Mat &templateImage, + double &bestScore, + int method) +{ + // 输入验证 + if (detectionImage.empty() || templateImage.empty()) + { + throw std::invalid_argument("输入图像不能为空"); + } + if (detectionImage.channels() != 1 || templateImage.channels() != 1) + { + throw std::invalid_argument("必须输入灰度图像"); + } + if (templateImage.rows > detectionImage.rows || + templateImage.cols > detectionImage.cols) + { + throw std::invalid_argument("模板尺寸不能大于被检测图像"); + } + + // cv::imwrite("detectionImage.png", detectionImage); + // cv::imwrite("templateImage.png", templateImage); + // 执行模板匹配 + cv::Mat resultMatrix; + cv::matchTemplate(detectionImage, templateImage, resultMatrix, method); + + // 确定极值搜索方式 + const bool findMinima = (method == cv::TM_SQDIFF || method == cv::TM_SQDIFF_NORMED); + + // 查找极值位置 + cv::Point extremaLoc = cv::Point(0, 0); + double extremaVal; + cv::minMaxLoc(resultMatrix, + findMinima ? &extremaVal : nullptr, + findMinima ? nullptr : &extremaVal, + findMinima ? &extremaLoc : nullptr, + findMinima ? nullptr : &extremaLoc); + + // 设置有效性检查阈值(可根据方法动态调整) + double threshold = 0.0; + switch (method) + { + case cv::TM_CCOEFF_NORMED: + threshold = 0.6; + break; // [-1, 1] + case cv::TM_CCORR_NORMED: + threshold = 0.7; + break; // [0, 1] + case cv::TM_SQDIFF_NORMED: + threshold = 0.2; + break; // [0, 1] + default: + threshold = 0.0; + } + + // 验证匹配有效性 + const bool isValid = findMinima ? (extremaVal <= threshold) : (extremaVal >= threshold); + + if (isValid) + { + bestScore = extremaVal; + return extremaLoc; + } + bestScore = -1; // 无效时的默认值 + return extremaLoc; +} diff --git a/AlgorithmModule/src/ALLImgCheckAnalysisy.cpp b/AlgorithmModule/src/ALLImgCheckAnalysisy.cpp new file mode 100644 index 0000000..3ed5e0b --- /dev/null +++ b/AlgorithmModule/src/ALLImgCheckAnalysisy.cpp @@ -0,0 +1,695 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:50:00 + * @LastEditTime: 2025-09-22 16:44:43 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/src/CamDeal.cpp + */ +#include "ALLImgCheckAnalysisy.hpp" +#include "CheckUtil.hpp" +#include "Define.h" +#include "AI_Factory.h" +#include + +std::vector m_FlawCodeList; + +std::vector QX_Result_Names = + { + "OK", + "aotudian", + "other", + "line", + "zangwu", + "edge", + "ymhs", + "dianzhuang", + "posun", + "xianwei", + "shuizi", + "danban", + "fuchen", + }; +std::vector QX_Result_Code = + { + "P0000", + "MA507", + "MA508", + "MA506", + "MA504", + "MA503", + "MA502", + "MA505", + "MA501", + "P0001", + "P0002", + "P0003", + "P0004", +}; + +int ReadFlawCodeConfig(std::string json_path) +{ + m_FlawCodeList.erase(m_FlawCodeList.begin(), m_FlawCodeList.end()); + std::string strPath = json_path; + printf("ReadFlawCodeConfig path %s\n", strPath.c_str()); + Json::CharReaderBuilder builder; + builder["collectComments"] = true; + Json::Value root; + std::string err; + std::ifstream ifs(strPath); + if (!ifs.is_open()) + { + printf("error:file is open\n"); + return 0; + } + if (!Json::parseFromStream(builder, ifs, &root, &err)) + { + printf("error:parseFromStream\n"); + return 0; + } + + for (int i = 0; i < root.size(); i++) + { + // printf("Node idx %d /%d \n", i, root.size()); + + ReadFlawCode tem; + tem.flaw_name = root[i]["zh_name"].asString(); + tem.flaw_code = root[i]["en_name"].asString(); + string desc = root[i]["desc"].asString(); + { + + std::istringstream stream(desc); + std::string token; + + // 使用 getline 按照分号分割 + while (std::getline(stream, token, ';')) + { + tem.config_flaw_name.push_back(token); + } + } + m_FlawCodeList.push_back(tem); + } + for(int i = 0; i < m_FlawCodeList.size(); i++) + { + if(i >= QX_Result_Names.size()) { + QX_Result_Names.push_back(m_FlawCodeList.at(i).flaw_name); + QX_Result_Code.push_back(m_FlawCodeList.at(i).flaw_code); + } + else + { + QX_Result_Names.at(i) = m_FlawCodeList.at(i).flaw_name; + QX_Result_Code.at(i) = m_FlawCodeList.at(i).flaw_code; + } + + } + return 0; +} + +double calculateDistanceBetweenRectCenters(const cv::Rect &rect1, const cv::Rect &rect2, float fx, float fy) +{ + // 计算矩形1的中心点 + cv::Point center1(rect1.x + rect1.width / 2, rect1.y + rect1.height / 2); + + // 计算矩形2的中心点 + cv::Point center2(rect2.x + rect2.width / 2, rect2.y + rect2.height / 2); + center1.x *= fx; + center1.y *= fy; + + center2.x *= fx; + center2.y *= fy; + + // 计算中心点之间的欧几里得距离 + double distance = cv::norm(center1 - center2); + + return distance; +} + +ALLImgCheckAnalysisy::ALLImgCheckAnalysisy() +{ + + m_strTest = ""; +} + +ALLImgCheckAnalysisy::~ALLImgCheckAnalysisy() +{ + StopThread(); +} + +int ALLImgCheckAnalysisy::RunStart(void *pconfig1) +{ + VERSION_INFO *pVersionconfig = (VERSION_INFO *)pconfig1; + if (pVersionconfig == NULL) + { + printf("**************************** \n"); + m_nErrorCode = CHECK_ERROR_VERSION; // 参数或接口版本问题 + return m_nErrorCode; + } + + int v1 = ALL_INTERFACE_VERSION; + int v2 = CONFIGBASE_VERSION; + int v3 = RESULT_VERSION; + printf("**************************** ALL_INTERFACE_VERSION so: %d in:%d CONFIGBASE_VERSION so:%d in:%d RESULT_VERSION so:%d in:%d\n", + v1, pVersionconfig->InterfaceVersion, v2, pVersionconfig->ConfigVersion, v3, pVersionconfig->ResultVersion); + // 版本控制 + if (pVersionconfig->InterfaceVersion != ALL_INTERFACE_VERSION || + pVersionconfig->ConfigVersion != CONFIGBASE_VERSION || + pVersionconfig->ResultVersion != RESULT_VERSION) + { + m_nErrorCode = CHECK_ERROR_VERSION; // 参数或接口版本问题 + return m_nErrorCode; + } + int re = 0; + + re = InitCameraCheckAnalysisy(); + if (re != 0) + { + printf("*************InitCameraCheckAnalysisy error %d*************** \n", re); + m_nErrorCode = INIT_CameraCheck_Error; + return m_nErrorCode; + } + + re = InitRun(); + if (CHECK_OK != re) + { + m_nErrorCode = re; + return m_nErrorCode; + } + re = InitAIFactory(); + if (CHECK_OK != re) + { + m_nErrorCode = re; + return m_nErrorCode; + } + m_nErrorCode = CHECK_OK; + printf(">>>> ALLImgCheckAnalysisy Start Succ \n"); + + m_nErrorCode = CHECK_OK; + m_bInitSucc = true; + return m_nErrorCode; +} + +int ALLImgCheckAnalysisy::SetDataRun_SharePtr(std::shared_ptr p) +{ + + int re = PushInImg_New(p); + + // printf("SetDataRun_SharePtr======================= re %d \n", re); + + return re; +} + +int ALLImgCheckAnalysisy::GetCheckReuslt(std::shared_ptr &pResult) +{ + std::unique_lock lk(mtx_CheckResult); // 使用 unique_lock + CheckResult_cond.wait(lk, [this] + { return !m_CheckResultList.empty(); }); // 等待直到数据队列非空 + pResult = m_CheckResultList.front(); // 从队列中取出数 + m_CheckResultList.pop(); + lk.unlock(); + return 0; +} + +int ALLImgCheckAnalysisy::ReJson(std::shared_ptr p, std::shared_ptr &pResult) +{ + + return 0; +} + +int ALLImgCheckAnalysisy::CheckImg(std::shared_ptr p, std::shared_ptr &pResult) +{ + + return 0; +} + +int ALLImgCheckAnalysisy::GetStatus() +{ + return 0; +} + +int ALLImgCheckAnalysisy::UpdateConfig(void *pconfig, int nConfigType) +{ + int re = 0; + RunInfoST *tempconfig; + switch (nConfigType) + { + case CHECK_CONFIG_Run: + tempconfig = (RunInfoST *)pconfig; + m_RunConfig.copy(*tempconfig); + break; + case CHECK_CONFIG_Module: + m_pConfigManager = (ConfigManagerBase *)pconfig; + break; + default: + break; + } + + return 0; +} + +std::string ALLImgCheckAnalysisy::GetVersion() +{ + return std::string("BOE_2.0.5"); +} + +std::string ALLImgCheckAnalysisy::GetErrorInfo() +{ + std::string result = ""; + + return result; +} + +int ALLImgCheckAnalysisy::ErrorReturn(std::shared_ptr p) +{ + + std::shared_ptr result = std::make_shared(); + result->in_shareImage = p; + result->checkStatus = 1; + result->nresult = -CHECK_ERROR_PushImg_ID_Error; + result->basicResult.img_id = p->img_id; + result->basicResult.imgtype = p->imgtype; + result->basicResult.imgstr = p->imgstr; + result->basicResult.strChannel = p->strChannel; + // printf("ErrorReturn==== %s %s\n", p->strImgProductID.c_str(), p->strChannel.c_str()); + { + std::lock_guard lock(mtx_CheckResult); + m_CheckResultList.push(result); + } + CheckResult_cond.notify_all(); + + return 0; +} + +std::shared_ptr ALLImgCheckAnalysisy::GetProduct(std::string strProduct) +{ + std::lock_guard lock(mtx_ProductList); + for (int i = 0; i < m_ProductList.size(); i++) + { + // printf("ddd %s \n", m_ProductList.at(i)->productBaseResult->strproductName.c_str()); + if (m_ProductList.at(i)->productBaseResult->strproductName == strProduct) + { + return m_ProductList.at(i); + } + } + + return std::shared_ptr(); +} + +int ALLImgCheckAnalysisy::InitAIFactory() +{ + std::shared_ptr AI_Factory; + AI_Factory = AIFactory::GetInstance(); + + GPU_Config gpu; + gpu.gpu_0 = true; + gpu.gpu_1 = true; + + AI_Factory->InitALLAIModle(gpu); + return 0; +} + +int ALLImgCheckAnalysisy::LoadRunConfig(void *p) +{ + return 0; +} + +int ALLImgCheckAnalysisy::LoadCheckConfig(void *p) +{ + return 0; +} + +int ALLImgCheckAnalysisy::InitRun() +{ + int re; + re = StartThread(); + if (CHECK_OK != re) + { + return re; + } + + return 0; +} + +int ALLImgCheckAnalysisy::StartCheck() +{ + return 0; +} + +int ALLImgCheckAnalysisy::SetIDLE() +{ + return 0; +} + +int ALLImgCheckAnalysisy::StartThread() +{ + m_bExit = false; + + { // 开启检测线程 + ptr_thread_Run = std::make_shared(std::bind(&ALLImgCheckAnalysisy::Run, this)); + } + + return 0; +} + +int ALLImgCheckAnalysisy::StopThread() +{ + m_bExit = true; + if (ptr_thread_Run != nullptr) + { + if (ptr_thread_Run->joinable()) + { + ptr_thread_Run->join(); + } + } + return 0; +} + +int ALLImgCheckAnalysisy::ExitSystem() +{ + return 0; +} + +int ALLImgCheckAnalysisy::InitCameraCheckAnalysisy() +{ + string defect_list_file = m_pConfigManager->GetJsonPath(); + if (defect_list_file == "") { + defect_list_file = "/var/aidlux/efs/model/defect_list.json"; + } + else{ + defect_list_file += "/defect_list.json"; + } + ReadFlawCodeConfig(defect_list_file); + m_pCameraCheckAnalysisyList.clear(); + for (const auto &config : m_pConfigManager->Config_instances_) + { + + std::cout << "key: " << config.first << std::endl; + std::shared_ptr p = std::make_shared(); + + p->m_RunConfig.copy(m_RunConfig); + p->m_pConfig = config.second; + int re = p->Init(config.first); + if (re != 0) + { + std::cout << "Init CameraCheckAnalysisy " << config.first << " Failed" << std::endl; + return -1; + } + m_pCameraCheckAnalysisyList[config.first] = p; + } + if (m_pCameraCheckAnalysisyList.size() <= 0) + { + printf("ALLImgCheckAnalysisy::InitCameraCheckAnalysisy error camera config is null \n"); + return 1; + /* code */ + } + + // for (const auto &pCameraCheckAnalysisy : m_pCameraCheckAnalysisyList) + // { + // std::cout << "key: " << pCameraCheckAnalysisy.first << std::endl; + // } + printf("ALLImgCheckAnalysisy::InitCameraCheckAnalysisy end \n"); + return 0; +} + +int ALLImgCheckAnalysisy::InitData() +{ + + return 0; +} + +int ALLImgCheckAnalysisy::Det_Product(std::shared_ptr &product) +{ + + // 处理每个相机 + while (true) + { + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + { + std::lock_guard lock(product->mtx_CameraResultList); // + for (auto &ptr : product->m_pCameraResultList) + { + if (ptr->GetCheckStep() == Check_Step_NODet) + { + m_pCameraCheckAnalysisyList[ptr->cameraBaseResult->strCameraName]->StartCheck(ptr); + } + } + } + + // 判断每个相机是否都处理完了。 + bool bdetComplete = product->bCheckCamplate(); + // 处理完成,退出循环 + if (bdetComplete) + { + break; + } + } + + // 联合分析 + // AnalysiyAll(0); + SetProductResult(product); + product->SetCheckEnd(); + string cur_time = CheckUtil::getCurTimeHMS(); + printf("[%s]>>>>>>>>>>>>>>>Det_Product****************det End************\n", cur_time.c_str()); + + return 0; +} + +std::shared_ptr ALLImgCheckAnalysisy::GetProduct() +{ + + std::unique_lock lk(mtx_ProductList); // 使用 unique_lock + ProductList_cond.wait(lk, [this] + { return !m_ProductList.empty(); }); // 等待直到数据队列非空 + std::shared_ptr tem = m_ProductList.at(0); + lk.unlock(); + return tem; +} + +int ALLImgCheckAnalysisy::AnalysiyAll(int productIdx) +{ + + return 0; +} + +int ALLImgCheckAnalysisy::SetProductResult(std::shared_ptr product) +{ + + int nDetCamNum = product->m_pCameraResultList.size(); + // 相机2的起始位置 + bool bNG = false; + for (int icam = 0; icam < nDetCamNum; icam++) + { + + std::shared_ptr pcam = product->m_pCameraResultList.at(icam); + for (int i = 0; i < pcam->ImageALLDetResultList.size(); i++) + { + + std::shared_ptr pCheckResult = pcam->ImageALLDetResultList.at(i)->result; + + if (pCheckResult->qxImageResult.size() > 0) + { + bNG = true; + } + if (bNG) + { + break; + } + } + if (bNG) + { + break; + } + } + if (bNG) + { + for (int icam = 0; icam < nDetCamNum; icam++) + { + + std::shared_ptr pcam = product->m_pCameraResultList.at(icam); + for (int i = 0; i < pcam->ImageALLDetResultList.size(); i++) + { + + std::shared_ptr pCheckResult = pcam->ImageALLDetResultList.at(i)->result; + pCheckResult->nProductResult = 1; + } + } + } + return 0; +} + +int ALLImgCheckAnalysisy::SetSetComplet_New(std::shared_ptr product, int nerror) +{ + if (product) + { + + int nDetCamNum = product->m_pCameraResultList.size(); + for (int icam = 0; icam < nDetCamNum; icam++) + { + std::shared_ptr pcam = product->m_pCameraResultList.at(icam); + for (int i = 0; i < pcam->ImageALLDetResultList.size(); i++) + { + std::shared_ptr pCheckResult = pcam->ImageALLDetResultList.at(i)->result; + + { + std::lock_guard lock123(mtx_CheckResult); + m_CheckResultList.push(pCheckResult); + } + CheckResult_cond.notify_all(); + } + } + } + + return 0; +} + +int ALLImgCheckAnalysisy::PushInImg_New(std::shared_ptr p) +{ + + if (!m_bInitSucc) + { + printf("Init fail exit \n"); + return CHECK_ERROR_Config_Null; + } + + std::string strlog = ""; + m_strTest += " PushInImg->SN:"; + m_strTest += p->strImgProductID; + m_strTest += " Channel:"; + m_strTest += p->strChannel; + m_strTest += " CameraID:"; + m_strTest += p->strCameraName; + std::string strBase = ""; + strBase += " PushInImg->SN:"; + strBase += p->strImgProductID; + strBase += " Channel:"; + strBase += p->strChannel; + printf("strBase %s p->Status %d\n", strBase.c_str(), p->Status); + std::shared_ptr product; + { + std::string strcameraName = p->strCameraName; + cout << "strcameraName: " << strcameraName << endl; + if(m_pCameraCheckAnalysisyList.size() <= 0){ + cout << "m_pCameraCheckAnalysisyList.size(): " << m_pCameraCheckAnalysisyList.size() << endl; + } + for (auto it = m_pCameraCheckAnalysisyList.begin(); it != m_pCameraCheckAnalysisyList.end(); ++it) { + std::cout << "m_pCameraCheckAnalysisyList_Key: " << it->first << std::endl; + } + // 判断 相机名称是否存在 + + if (!m_pCameraCheckAnalysisyList.count(strcameraName) && -1 != p->Status) + { + return CHECK_ERROR_Camear_ID_Error; + } + + product = GetProduct(p->strImgProductID); + bool ProductID_Exist = false; // 是否存在当前产品ID + if (product) + { + ProductID_Exist = true; + } + + // 产品存在 并且 模式 是第一张图, 则,返回异常。 + if (IN_IMG_Status_Start == p->Status && ProductID_Exist) + { + return CHECK_ERROR_PRODUCT_ID_EXIST; + } + // 产品存在,但是 图片都已经完了的状态 + if (ProductID_Exist && product->bIsImgComplete) + { + ErrorReturn(p); + return CHECK_ERROR_PRODUCT_ID_EXIST; + } + // 产品不存在 新建一个 + if (!product) + { + std::lock_guard lock(mtx_ProductList); + { + if (m_ProductList.size() > 5) + { + + return CHECK_ERROR_PushImg_ListSize; + } + } + product = std::make_shared(); + product->productBaseResult->strproductName = p->strImgProductID; + m_ProductList.push_back(product); + std::string strTimg = CheckUtil::getCurTimeHMS(); + product->productBaseResult->detlog->AddCheckstr(PrintLevel_0, "PushInImg", "add new product %s %s ", p->strImgProductID.c_str(), strTimg.c_str()); + } + // 送入图的状态 不是结束 + if (-1 != p->Status) + { + // 对应相机的 检测结果 + std::shared_ptr pCamera = product->GetCameraResult(strcameraName); + + if (pCamera.get() == nullptr) + { + ErrorReturn(p); + return CHECK_ERROR_Camear_ID_Error; + } + // 添加产品信息 + pCamera->AddDetImage(p); + } + product->UpdatePushStatus(p->Status); + if (-1 == p->Status || IN_IMG_Status_End == p->Status) + { + m_strTest += "\n"; + product->AddLog(m_strTest); + m_strTest = ""; + } + + ProductList_cond.notify_all(); + } + + return 0; +} + +int ALLImgCheckAnalysisy::Run() +{ + + while (!m_bExit) + { + + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + + std::shared_ptr product = GetProduct(); + + int re = Det_Product(product); + // // 检测失败 + // if (re != 0) + // { + // continue; + // } + SetSetComplet_New(product, re); + + // 更新 产品队列 + { + std::lock_guard lock(mtx_ProductList); // + if (!m_ProductList.empty()) + { + m_ProductList.erase(m_ProductList.begin()); + } + } + } + + return 0; +} +int ALLImgCheckAnalysisy::set_cpu_id(const std::vector &cpu_set_vec) +{ + // for cpu affinity + int nRet = 0; +#ifdef __linux + cpu_set_t _cur_cpu_set; + CPU_ZERO(&_cur_cpu_set); + for (auto _id : cpu_set_vec) + { + CPU_SET(_id, &_cur_cpu_set); + } + if (0 > pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &_cur_cpu_set)) + { + perror("set cpu affinity failed: "); + printf("Warning: set cpu affinity failed ... ...\n"); + nRet = -1; + } +#endif //__linux + return nRet; +} diff --git a/AlgorithmModule/src/Blob.c b/AlgorithmModule/src/Blob.c new file mode 100644 index 0000000..4a44dd1 --- /dev/null +++ b/AlgorithmModule/src/Blob.c @@ -0,0 +1,979 @@ +#include +#include +#include +#include "BlobBase.h" +void pretest(double x) +{ + printf("fff %f \n", x); +} + +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#define min(a, b) (((a) < (b)) ? (a) : (b)) + +static inline int GetType(int nvalue, int *qx_list) +{ + // int re = 0; + // if ((nvalue & Value_ERR_TYPE_1) != 0) + // { + // re = 1; + // qx_list[ERR_TYPE_1] = 1; + // } + // else + // { + // qx_list[ERR_TYPE_1] = 0; + // } + // if ((nvalue & Value_ERR_TYPE_2) != 0) + // { + // re = 1; + // qx_list[ERR_TYPE_2] = 1; + // } + // else + // { + // qx_list[ERR_TYPE_2] = 0; + // } + + // return re; + qx_list[ERR_TYPE_1] = !!(nvalue & Value_ERR_TYPE_1); + qx_list[ERR_TYPE_2] = !!(nvalue & Value_ERR_TYPE_2); + + return qx_list[ERR_TYPE_1] | qx_list[ERR_TYPE_2]; +} +//-------------sxg added + +void AddErrorScan(ERROR_DOTS_SCAN_ROW *curRow, ERROR_DOTS_SCAN_ROW *prevRow, int x, int len, int y, int difSum, int minArea, int minEng, int mdx, int *pErrClass) +{ + + if (curRow->scanCount < _MAX_ERROR_SCAN_LINE_PER_ROW) + { + + int lastScanLineIndex = curRow->scanCount++; + ERROR_DOTS_SCAN_DATA *scan = curRow->errorScanLineTab + lastScanLineIndex; + scan->x = x; + scan->count = len; + int ex = x + len - 1; + scan->energy = difSum; + scan->area = scan->count; + scan->xposSum = (x + (len >> 1)) * len; + scan->yposSum = y * len; + scan->minx = x; + scan->miny = y; + scan->maxx = ex; + scan->maxy = y; + scan->macro = mdx; + for (int ec = 0; ec < _MAX_ERR_CLASS; ec++) + { + scan->ErrClass[ec] = pErrClass[ec]; + } + + curRow->macro[scan->macro] = len; + + int linkIndexTab[_MAX_ERROR_SCAN_LINE_PER_ROW]; + int linkCount = 0; + if (prevRow) + { + for (int t = 0; t < _MAX_MACRO_COUNT; t++) + { + curRow->macro[t] += prevRow->macro[t]; + // prevRow->macro[t]=0; + } + + int prevLastScanLineIndex = prevRow->scanCount - 1; + ERROR_DOTS_SCAN_DATA *pscan = prevRow->errorScanLineTab + prevLastScanLineIndex; + for (; prevLastScanLineIndex >= 0; --prevLastScanLineIndex, --pscan) + { + int psx = pscan->x - 1; + int pex = psx + pscan->count - 1 + 1; + // sxg modified waitting for valid 9.5 + if (x <= pex && ex >= psx) + { + if (pscan->area > 0) + { + int area = scan->area + (pscan->area); + scan->area = area; + if (scan->macro != pscan->macro) + { + if (scan->macro < pscan->macro) + scan->macro = pscan->macro; + } + scan->energy += pscan->energy; + scan->xposSum += pscan->xposSum; + scan->yposSum += pscan->yposSum; + scan->minx = min(scan->minx, pscan->minx); + scan->miny = min(scan->miny, pscan->miny); + scan->maxx = max(scan->maxx, pscan->maxx); + scan->maxy = max(scan->maxy, pscan->maxy); + pscan->area = 0; + pscan->energy = lastScanLineIndex; + for (int ec = 0; ec < _MAX_ERR_CLASS; ec++) + { + scan->ErrClass[ec] = pErrClass[ec] + (pscan->ErrClass[ec]); + } + linkIndexTab[/*0xff & */ (linkCount++)] = prevLastScanLineIndex; + } + // else + //{ + // int bindex = 0xff & pscan->energy; + // ERROR_DOTS_SCAN_DATA * hscan = curRow->errorScanLineTab + bindex; + // hscan->count = ex - hscan->x + 1; + // hscan->area += scan->area; + // hscan->energy += scan->energy; + // hscan->xposSum += scan->xposSum; + // hscan->yposSum += scan->yposSum; + // hscan->minx = min(scan->minx , hscan->minx); + // hscan->miny = min(scan->miny , hscan->miny); + // hscan->maxx = max(scan->maxx , hscan->maxx); + // hscan->maxy = max(scan->maxy , hscan->maxy); + // scan->area = 0; + // for(;linkCount > 0 ; --linkCount) + // { + // ERROR_DOTS_SCAN_DATA * p = prevRow->errorScanLineTab + linkIndexTab[0xff & (linkCount - 1)]; + // p->energy = bindex; + // } + // curRow->scanCount--; + // break; + // } + } + } + } + } +} + +void LinkScanLineToBlob(ERROR_DOTS_BLOBS *blobs, ERROR_DOTS_SCAN_ROW *prevRow, int sx, int sy, int minArea, int minEnergy, int mergeDistanceX, int mergeDistanceY, int width) +{ + if (prevRow) + { + int prevLastScanLineIndex = prevRow->scanCount - 1; + ERROR_DOTS_SCAN_DATA *pscan = prevRow->errorScanLineTab + prevLastScanLineIndex; + // int minArea = param->minArea; + // int minEnergy = param->minEnergy; + for (; prevLastScanLineIndex >= 0; --prevLastScanLineIndex, --pscan) + { + if (pscan->area > 0) + { + int x = pscan->xposSum / pscan->area + sx; + int y = pscan->yposSum / pscan->area + sy; + int minx = pscan->minx + sx; + int miny = pscan->miny + sy; + int maxx = pscan->maxx + sx; + int maxy = pscan->maxy + sy; + if (x < width) + { + int blobIndex = blobs->blobCount; + // int mergeDistance = param->mergeDistance; + ERROR_DOTS_BLOB_DATA *pblob = blobs->blobTab + blobIndex - 1; + int left = minx - mergeDistanceX, right = maxx + mergeDistanceX; + int top = miny - mergeDistanceY, bottom = maxy + mergeDistanceY; + for (int i = blobIndex - 1; i >= 0; --i, --pblob) + { + + if (1) + { + if (pblob->maxy > top && pblob->miny < bottom) + { + if (pblob->maxx > left && pblob->minx < right) + { + int area = pblob->area + pscan->area; + pblob->x = (pblob->x * pblob->area + x * pscan->area) / area; + pblob->y = (pblob->y * pblob->area + y * pscan->area) / area; + pblob->area = area; + for (int ec = 0; ec < _MAX_ERR_CLASS; ec++) + { + pblob->ErrClass[ec] += pscan->ErrClass[ec]; + } + + pblob->energy += pscan->energy; + pblob->minx = min(pblob->minx, minx); + pblob->miny = min(pblob->miny, miny); + pblob->maxx = max(pblob->maxx, maxx); + pblob->maxy = max(pblob->maxy, maxy); + pblob->macro[pscan->macro] += prevRow->macro[pscan->macro]; + prevRow->macro[pscan->macro] -= pscan->area; + blobIndex = _MAX_ERROR_DOT_BLOB; + break; + } + } + } + } + if (pscan->area > minArea /*|| pscan->energy > minEnergy*/) + { + if (blobIndex < _MAX_ERROR_DOT_BLOB) + { + pblob = blobs->blobTab + blobIndex; + pblob->x = x; + pblob->y = y; + pblob->area = pscan->area; + pblob->energy = pscan->energy; + pblob->minx = minx; + pblob->miny = miny; + pblob->maxx = maxx; + pblob->maxy = maxy; + blobs->blobCount++; + for (int t = 0; t < _MAX_MACRO_COUNT; t++) + { + pblob->macro[t] = 0; + } + pblob->macro[pscan->macro] = pscan->area; + prevRow->macro[pscan->macro] -= pscan->area; + // prevRow->macro[pscan->macro]=0; + for (int ec = 0; ec < _MAX_ERR_CLASS; ec++) + { + pblob->ErrClass[ec] = pscan->ErrClass[ec]; + } + } + } + } + } + pscan->area = 0; + for (int ec = 0; ec < _MAX_ERR_CLASS; ec++) + { + pscan->ErrClass[ec] = 0; + } + } + // for (int t=0;tmacro[t]+=prevRow->macro[t]; + // prevRow->macro[t]=0; + // } + } +} + +void MergeBlob(ERROR_DOTS_BLOBS *blobs, ERROR_DOTS_BLOB_PARAM *param) +{ + int count = blobs->blobCount; + ERROR_DOTS_BLOB_DATA *blob = blobs->blobTab + count - 1; + int pace = param->mergeDistance; + for (int i = count - 1; i > 0; --i, --blob) + { + int minx = blob->minx; + int miny = blob->miny; + int maxx = blob->maxx; + int maxy = blob->maxy; + int energy = blob->energy; + + int left = minx - pace, right = maxx + pace; + int top = miny - 1, bottom = maxy + 1; + ERROR_DOTS_BLOB_DATA *pblob = blob - 1; + for (int j = i - 1; j >= 0; --j, --pblob) + { + + if (pblob->ErrType == blob->ErrType) + { + if (pblob->maxy > top && pblob->miny < bottom) + { + if (pblob->maxx > left && pblob->minx < right) + { + int areaSum = pblob->area + blob->area; + int x = blob->x, y = blob->y; + pblob->x = (pblob->x * pblob->area + x * blob->area) / areaSum; + pblob->y = (pblob->y * pblob->area + y * blob->area) / areaSum; + pblob->area = areaSum; + for (int ec = 0; ec < _MAX_ERR_CLASS; ec++) + { + pblob->ErrClass[ec] += blob->ErrClass[ec]; + } + + pblob->energy += energy; + pblob->minx = min(pblob->minx, minx); + pblob->miny = min(pblob->miny, miny); + pblob->maxx = max(pblob->maxx, maxx); + pblob->maxy = max(pblob->maxy, maxy); + for (int t = 0; t < _MAX_MACRO_COUNT; t++) + { + pblob->macro[t] += blob->macro[t]; + blob->macro[t] = 0; + } + count--; + memmove(blob, blob + 1, (count - i) * sizeof(blob[0])); + break; + } + } + } + } + } + blobs->blobCount = count; +} +// static int __cdecl compareBlob(const void * p1, const void * p2) +static int compareBlob(const void *p1, const void *p2) +{ + ERROR_DOTS_BLOB_DATA *b1 = (ERROR_DOTS_BLOB_DATA *)p1; + ERROR_DOTS_BLOB_DATA *b2 = (ERROR_DOTS_BLOB_DATA *)p2; + return (b2->area) - (b1->area); +} + +void SortBlob(ERROR_DOTS_BLOBS *blobs) +{ + int count = blobs->blobCount; + ERROR_DOTS_BLOB_DATA *blob = blobs->blobTab; + qsort(blob, count, sizeof(blob[0]), compareBlob); +} + +// 当前行和前面行合并 +void AddErrorScan_New(ERROR_DOTS_SCAN_ROW *curRow, ERROR_DOTS_SCAN_ROW *prevRow, int x, int len, int y, int difSum, int minArea, int minEng, int errorType) +{ + if (curRow->scanCount < _MAX_ERROR_SCAN_LINE_PER_ROW) + { + + int lastScanLineIndex = curRow->scanCount++; + ERROR_DOTS_SCAN_DATA *scan = curRow->errorScanLineTab + lastScanLineIndex; + scan->x = x; + scan->count = len; + int ex = x + len - 1; + scan->energy = difSum; + scan->area = scan->count; + scan->xposSum = (x + (len >> 1)) * len; + scan->yposSum = y * len; + scan->minx = x; + scan->miny = y; + scan->maxx = ex; + scan->maxy = y; + scan->type = errorType; + + if (prevRow) + { + int prevLastScanLineIndex = prevRow->scanCount - 1; + ERROR_DOTS_SCAN_DATA *pscan = prevRow->errorScanLineTab + prevLastScanLineIndex; + for (; prevLastScanLineIndex >= 0; --prevLastScanLineIndex, --pscan) + { + int psx = pscan->x - 1; + int pex = psx + pscan->count - 1 + 1; + if (x <= pex && ex >= psx && pscan->type == scan->type) + { + if (pscan->area > 0) + { + int area = scan->area + (pscan->area); + scan->area = area; + scan->energy += pscan->energy; + scan->xposSum += pscan->xposSum; + scan->yposSum += pscan->yposSum; + scan->minx = min(scan->minx, pscan->minx); + scan->miny = min(scan->miny, pscan->miny); + scan->maxx = max(scan->maxx, pscan->maxx); + scan->maxy = max(scan->maxy, pscan->maxy); + pscan->area = 0; + pscan->energy = lastScanLineIndex; + } + } + } + } + } +} + +void LinkScanLineToBlob_New(ERROR_DOTS_BLOBS *blobs, ERROR_DOTS_SCAN_ROW *prevRow, int sx, int sy, int minArea, int minEnergy, int mergeDistanceX, int mergeDistanceY, int width) +{ + if (prevRow) + { + int prevLastScanLineIndex = prevRow->scanCount - 1; + ERROR_DOTS_SCAN_DATA *pscan = prevRow->errorScanLineTab + prevLastScanLineIndex; + // int minArea = param->minArea; + // int minEnergy = param->minEnergy; + for (; prevLastScanLineIndex >= 0; --prevLastScanLineIndex, --pscan) + { + if (pscan->area > 0) + { + int x = pscan->xposSum / pscan->area + sx; + int y = pscan->yposSum / pscan->area + sy; + int minx = pscan->minx + sx; + int miny = pscan->miny + sy; + int maxx = pscan->maxx + sx; + int maxy = pscan->maxy + sy; + if (x < width) + { + int blobIndex = blobs->blobCount; + // int mergeDistance = param->mergeDistance; + ERROR_DOTS_BLOB_DATA *pblob = blobs->blobTab + blobIndex - 1; + int left = minx - mergeDistanceX, right = maxx + mergeDistanceX; + int top = miny - mergeDistanceY, bottom = maxy + mergeDistanceY; + for (int i = blobIndex - 1; i >= 0; --i, --pblob) + { + if (pblob->ErrType == pscan->type) + { + if (pblob->maxy > top && pblob->miny < bottom) + { + if (pblob->maxx > left && pblob->minx < right) + { + int area = pblob->area + pscan->area; + pblob->x = (pblob->x * pblob->area + x * pscan->area) / area; + pblob->y = (pblob->y * pblob->area + y * pscan->area) / area; + pblob->area = area; + // for (int ec = 0; ec < _MAX_ERR_CLASS; ec++) + // { + // pblob->ErrClass[ec] += pscan->ErrClass[ec]; + // } + + pblob->energy += pscan->energy; + pblob->minx = min(pblob->minx, minx); + pblob->miny = min(pblob->miny, miny); + pblob->maxx = max(pblob->maxx, maxx); + pblob->maxy = max(pblob->maxy, maxy); + // pblob->macro[pscan->macro] += prevRow->macro[pscan->macro]; + // prevRow->macro[pscan->macro] -= pscan->area; + blobIndex = _MAX_ERROR_DOT_BLOB; + break; + } + } + } + } + if (pscan->area > minArea /*|| pscan->energy > minEnergy*/) + { + if (blobIndex < _MAX_ERROR_DOT_BLOB) + { + pblob = blobs->blobTab + blobIndex; + pblob->x = x; + pblob->y = y; + pblob->area = pscan->area; + pblob->energy = pscan->energy; + pblob->ErrType = pscan->type; + pblob->minx = minx; + pblob->miny = miny; + pblob->maxx = maxx; + pblob->maxy = maxy; + blobs->blobCount++; + // for (int t = 0; t < _MAX_MACRO_COUNT; t++) + // { + // pblob->macro[t] = 0; + // } + // pblob->macro[pscan->macro] = pscan->area; + // prevRow->macro[pscan->macro] -= pscan->area; + // prevRow->macro[pscan->macro]=0; + // for (int ec = 0; ec < _MAX_ERR_CLASS; ec++) + // { + // pblob->ErrClass[ec] = pscan->ErrClass[ec]; + // } + } + } + } + } + pscan->area = 0; + for (int ec = 0; ec < _MAX_ERR_CLASS; ec++) + { + pscan->ErrClass[ec] = 0; + } + } + // for (int t=0;tmacro[t]+=prevRow->macro[t]; + // prevRow->macro[t]=0; + // } + } +} + +int GetBlobs_V2(ERROR_DOTS_BLOBS *blobs, unsigned char *pImgdata, unsigned char *pErrordata, int width, int height, int basev, int minArea) +{ + + if (blobs == NULL || pErrordata == NULL) + { + return 1; + } + int pitch = width; + int offset; + + int point_is_err = 0; + int wLineErrsList = 0; + int errPos_xList = 0; + int difSumList = 0; + int point_is_errList = 0; + + // memset(blobs, 0x00, sizeof(ERROR_DOTS_BLOBS)); + + ERROR_DOTS_SCAN_ROW rowDataTab[2]; + ERROR_DOTS_SCAN_ROW *curRow = 0; + ERROR_DOTS_SCAN_ROW *prevRow = 0; + + int MIN_AREA = minArea; + if (minArea <= 0) + { + MIN_AREA = 10; + } + + int minEnergy = 2; + int mergeDistanceX = 1; + int mergeDistanceY = 1; + offset = 0; + int nErrorType = 0; + int lasttype = -1; + + for (int y = 0; y < height; y++) + { + wLineErrsList = 0; + difSumList = 0; + curRow = rowDataTab + (y & 1); + curRow->scanCount = 0; + offset = y * pitch - 1; + nErrorType = -1; + lasttype = -1; + int kh = 0; + for (int x = 0; x < width; x++) + { + offset++; + point_is_err = 0; + if (pErrordata[offset] != 0 && pImgdata[offset] > basev) + { + point_is_err = 1; + difSumList += 1; + wLineErrsList++; + errPos_xList = x; + kh = 1; + } + else // 没有残点 所有缺陷都需要判断是否截止 + { + // 当前点 该缺陷类型 为FALSE 并且 改缺陷类型 有过残点 + if (wLineErrsList > 0) + { + AddErrorScan_New(curRow, prevRow, errPos_xList - wLineErrsList + 1, wLineErrsList, y, difSumList, 0, 0, ERR_TYPE_1); + wLineErrsList = 0; + difSumList = 0; + } + kh = 0; + } + + if (x == width - 1) + { + if (wLineErrsList > 0) + { + AddErrorScan_New(curRow, prevRow, errPos_xList - wLineErrsList + 1, wLineErrsList, y, difSumList, 0, 0, ERR_TYPE_1); + } + } + } + + LinkScanLineToBlob_New(blobs, prevRow, 0, 0, MIN_AREA, minEnergy, mergeDistanceX, mergeDistanceY, width); + + prevRow = curRow; + } + + LinkScanLineToBlob_New(blobs, prevRow, 0, 0, MIN_AREA, minEnergy, mergeDistanceX, mergeDistanceY, width); + ERROR_DOTS_BLOB_PARAM blobParam; + memset(&blobParam, 0x00, sizeof(ERROR_DOTS_BLOB_PARAM)); + blobParam.mergeDistance = 1; + MergeBlob(blobs, &blobParam); + SortBlob(blobs); + + return 0; +} + +int GetBlobs_V3(ERROR_DOTS_BLOBS *blobs, unsigned char *pErrordata, int width, int height, int minArea) +{ + + if (blobs == NULL || pErrordata == NULL) + { + return 1; + } + int pitch = width; + int offset; + + int point_is_err = 0; + int wLineErrsList = 0; + int errPos_xList = 0; + int difSumList = 0; + int point_is_errList = 0; + + // memset(blobs, 0x00, sizeof(ERROR_DOTS_BLOBS)); + + ERROR_DOTS_SCAN_ROW rowDataTab[2]; + ERROR_DOTS_SCAN_ROW *curRow = 0; + ERROR_DOTS_SCAN_ROW *prevRow = 0; + + int MIN_AREA = minArea; + if (minArea <= 0) + { + MIN_AREA = 10; + } + + int minEnergy = 2; + int mergeDistanceX = 20; + int mergeDistanceY = 20; + offset = 0; + int nErrorType = 0; + int lasttype = -1; + + for (int y = 0; y < height; y++) + { + wLineErrsList = 0; + difSumList = 0; + curRow = rowDataTab + (y & 1); + curRow->scanCount = 0; + offset = y * pitch - 1; + nErrorType = -1; + lasttype = -1; + int kh = 0; + for (int x = 0; x < width; x++) + { + offset++; + point_is_err = 0; + if (pErrordata[offset] != 0) + { + point_is_err = 1; + difSumList += 1; + wLineErrsList++; + errPos_xList = x; + kh = 1; + } + else // 没有残点 所有缺陷都需要判断是否截止 + { + // 当前点 该缺陷类型 为FALSE 并且 改缺陷类型 有过残点 + if (wLineErrsList > 0) + { + AddErrorScan_New(curRow, prevRow, errPos_xList - wLineErrsList + 1, wLineErrsList, y, difSumList, 0, 0, ERR_TYPE_1); + wLineErrsList = 0; + difSumList = 0; + } + kh = 0; + } + + if (x == width - 1) + { + if (wLineErrsList > 0) + { + AddErrorScan_New(curRow, prevRow, errPos_xList - wLineErrsList + 1, wLineErrsList, y, difSumList, 0, 0, ERR_TYPE_1); + } + } + } + + LinkScanLineToBlob_New(blobs, prevRow, 0, 0, MIN_AREA, minEnergy, mergeDistanceX, mergeDistanceY, width); + + prevRow = curRow; + } + + LinkScanLineToBlob_New(blobs, prevRow, 0, 0, MIN_AREA, minEnergy, mergeDistanceX, mergeDistanceY, width); + ERROR_DOTS_BLOB_PARAM blobParam; + memset(&blobParam, 0x00, sizeof(ERROR_DOTS_BLOB_PARAM)); + blobParam.mergeDistance = 1; + MergeBlob(blobs, &blobParam); + SortBlob(blobs); + + return 0; +} + +int GetBlobs_V3_CA(ERROR_DOTS_BLOBS *blobs, unsigned char *pErrordata, int width, int height, int minArea, int err_1_value, int err_2_value) +{ + + if (blobs == NULL || pErrordata == NULL) + { + return 1; + } + int pitch = width; + int offset; + + int point_is_err = 0; + int wLineErrsList = 0; + int errPos_xList = 0; + int difSumList = 0; + int point_is_errList = 0; + + // memset(blobs, 0x00, sizeof(ERROR_DOTS_BLOBS)); + + ERROR_DOTS_SCAN_ROW rowDataTab[2]; + ERROR_DOTS_SCAN_ROW *curRow = 0; + ERROR_DOTS_SCAN_ROW *prevRow = 0; + + int MIN_AREA = minArea; + if (minArea <= 0) + { + MIN_AREA = 10; + } + + int minEnergy = 2; + int mergeDistanceX = 20; + int mergeDistanceY = 20; + offset = 0; + int nErrorType = 0; + int lasttype = -1; + + for (int y = 0; y < height; y++) + { + wLineErrsList = 0; + difSumList = 0; + curRow = rowDataTab + (y & 1); + curRow->scanCount = 0; + offset = y * pitch - 1; + nErrorType = -1; + lasttype = -1; + int kh = 0; + for (int x = 0; x < width; x++) + { + offset++; + point_is_err = 0; + if (pErrordata[offset] == err_1_value || pErrordata[offset] == err_2_value) + { + point_is_err = 1; + difSumList += 1; + wLineErrsList++; + errPos_xList = x; + kh = 1; + } + else // 没有残点 所有缺陷都需要判断是否截止 + { + // 当前点 该缺陷类型 为FALSE 并且 改缺陷类型 有过残点 + if (wLineErrsList > 0) + { + AddErrorScan_New(curRow, prevRow, errPos_xList - wLineErrsList + 1, wLineErrsList, y, difSumList, 0, 0, ERR_TYPE_1); + wLineErrsList = 0; + difSumList = 0; + } + kh = 0; + } + + if (x == width - 1) + { + if (wLineErrsList > 0) + { + AddErrorScan_New(curRow, prevRow, errPos_xList - wLineErrsList + 1, wLineErrsList, y, difSumList, 0, 0, ERR_TYPE_1); + } + } + } + + LinkScanLineToBlob_New(blobs, prevRow, 0, 0, MIN_AREA, minEnergy, mergeDistanceX, mergeDistanceY, width); + + prevRow = curRow; + } + + LinkScanLineToBlob_New(blobs, prevRow, 0, 0, MIN_AREA, minEnergy, mergeDistanceX, mergeDistanceY, width); + ERROR_DOTS_BLOB_PARAM blobParam; + memset(&blobParam, 0x00, sizeof(ERROR_DOTS_BLOB_PARAM)); + blobParam.mergeDistance = 1; + MergeBlob(blobs, &blobParam); + SortBlob(blobs); + + return 0; +} + +int GetBlobs_ALL_New(ERROR_DOTS_BLOBS *blobs, unsigned char *pErrordata, unsigned char *pHdata, int width, int height, int minArea) +{ + if (blobs == NULL || pErrordata == NULL || pHdata == NULL) + { + return 1; + } + int pitch = width; + int offset; + + int point_is_err = 0; + int wLineErrsList[ERR_TYPE_COUNT] = {0}; + int errPos_xList[ERR_TYPE_COUNT] = {0}; + int difSumList[ERR_TYPE_COUNT] = {0}; + + memset(blobs, 0x00, sizeof(ERROR_DOTS_BLOBS)); + + ERROR_DOTS_SCAN_ROW rowDataTab[2]; + ERROR_DOTS_SCAN_ROW *curRow = 0; + ERROR_DOTS_SCAN_ROW *prevRow = 0; + + // int MIN_AREA = 2; + int MIN_AREA = minArea; + if (minArea <= 0) + { + MIN_AREA = 10; + } + int minEnergy = 2; + int mergeDistanceX = 25; + int mergeDistanceY = 25; + offset = 0; + int nErrorType = 0; + int lasttype = -1; + int qx_list[ERR_TYPE_COUNT] = {0}; + int kv = 0; + for (int y = 0; y < height; y++) + { + if (kv == 1) + { + memset(&wLineErrsList, 0, sizeof(int) * ERR_TYPE_COUNT); + memset(&difSumList, 0, sizeof(int) * ERR_TYPE_COUNT); + } + unsigned char *p = pErrordata + y * pitch; + curRow = rowDataTab + (y & 1); + curRow->scanCount = 0; + offset = y * pitch; + nErrorType = -1; + lasttype = -1; + kv = 0; + // 表示 这一行缺陷残点 + if (pHdata[y]) + { + for (int x = 0; x < width; x++, p++) + { + point_is_err = 0; + if (*p) + { + point_is_err = GetType(*p, qx_list); + kv = 1; + for (int qx_i = 0; qx_i < ERR_TYPE_COUNT; qx_i++) + { + if (qx_list[qx_i] > 0) + { + difSumList[qx_i] += 1; + wLineErrsList[qx_i]++; + errPos_xList[qx_i] = x; + } + } + } + else if (kv == 1) // 这一行有残点 + { + for (int qx_i = 0; qx_i < ERR_TYPE_COUNT; qx_i++) + { + if (wLineErrsList[qx_i] > 0) + { + + AddErrorScan_New(curRow, prevRow, errPos_xList[qx_i] - wLineErrsList[qx_i] + 1, wLineErrsList[qx_i], y, difSumList[qx_i], 0, 0, qx_i); + wLineErrsList[qx_i] = 0; + difSumList[qx_i] = 0; + } + if (!wLineErrsList[ERR_TYPE_1] && !wLineErrsList[ERR_TYPE_2]) + { + kv = 0; + } + } + } + if (x == width - 1) + { + for (int qx_i = 0; qx_i < ERR_TYPE_COUNT; qx_i++) + { + if (wLineErrsList[qx_i] > 0) + { + AddErrorScan_New(curRow, prevRow, errPos_xList[qx_i] - wLineErrsList[qx_i] + 1, wLineErrsList[qx_i], y, difSumList[qx_i], 0, 0, qx_i); + } + } + } + + // offset++; + } + } + + LinkScanLineToBlob_New(blobs, prevRow, 0, 0, MIN_AREA, minEnergy, mergeDistanceX, mergeDistanceY, width); + + prevRow = curRow; + } + + LinkScanLineToBlob_New(blobs, prevRow, 0, 0, MIN_AREA, minEnergy, mergeDistanceX, mergeDistanceY, width); + ERROR_DOTS_BLOB_PARAM blobParam; + memset(&blobParam, 0x00, sizeof(ERROR_DOTS_BLOB_PARAM)); + blobParam.mergeDistance = 1; + blobs->srcBlobCount = blobs->blobCount; + MergeBlob(blobs, &blobParam); + SortBlob(blobs); + return 0; +} + +int GetBlobs_oneLabe(ERROR_DOTS_BLOBS *blobs, unsigned char *pErrordata, unsigned char *pHdata, int width, int height, int minArea) +{ + if (blobs == NULL || pErrordata == NULL || pHdata == NULL) + { + return 1; + } + + int pitch = width; + int offset; + + int point_is_err = 0; + int wLineErrsList = 0; + int errPos_xList = 0; + int difSumList = 0; + int point_is_errList = 0; + + // memset(blobs, 0x00, sizeof(ERROR_DOTS_BLOBS)); + + ERROR_DOTS_SCAN_ROW rowDataTab[2]; + ERROR_DOTS_SCAN_ROW *curRow = 0; + ERROR_DOTS_SCAN_ROW *prevRow = 0; + + int MIN_AREA = minArea; + if (minArea <= 0) + { + MIN_AREA = 10; + } + + int minEnergy = 2; + int mergeDistanceX = 20; + int mergeDistanceY = 20; + offset = 0; + int nErrorType = 0; + int lasttype = -1; + + for (int y = 0; y < height; y++) + { + wLineErrsList = 0; + difSumList = 0; + curRow = rowDataTab + (y & 1); + curRow->scanCount = 0; + offset = y * pitch - 1; + nErrorType = -1; + lasttype = -1; + int kh = 0; + // 表示 这一行缺陷残点 + if (pHdata[y]) + { + for (int x = 0; x < width; x++) + { + offset++; + point_is_err = 0; + if (pErrordata[offset] != 0) + { + point_is_err = 1; + difSumList += 1; + wLineErrsList++; + errPos_xList = x; + kh = 1; + } + else // 没有残点 所有缺陷都需要判断是否截止 + { + // 当前点 该缺陷类型 为FALSE 并且 改缺陷类型 有过残点 + if (wLineErrsList > 0) + { + AddErrorScan_New(curRow, prevRow, errPos_xList - wLineErrsList + 1, wLineErrsList, y, difSumList, 0, 0, ERR_TYPE_1); + wLineErrsList = 0; + difSumList = 0; + } + kh = 0; + } + + if (x == width - 1) + { + if (wLineErrsList > 0) + { + AddErrorScan_New(curRow, prevRow, errPos_xList - wLineErrsList + 1, wLineErrsList, y, difSumList, 0, 0, ERR_TYPE_1); + } + } + } + } + + LinkScanLineToBlob_New(blobs, prevRow, 0, 0, MIN_AREA, minEnergy, mergeDistanceX, mergeDistanceY, width); + + prevRow = curRow; + } + + LinkScanLineToBlob_New(blobs, prevRow, 0, 0, MIN_AREA, minEnergy, mergeDistanceX, mergeDistanceY, width); + ERROR_DOTS_BLOB_PARAM blobParam; + memset(&blobParam, 0x00, sizeof(ERROR_DOTS_BLOB_PARAM)); + blobParam.mergeDistance = 1; + blobs->srcBlobCount = blobs->blobCount; + MergeBlob(blobs, &blobParam); + SortBlob(blobs); + return 0; +} + +int PushBlob(ERROR_DOTS_BLOBS *blobs, ERROR_DOTS_BLOBS *addblobs) +{ + for (int i = 0; i < addblobs->blobCount; i++) + { + int bhave = 0; + for (int j = 0; j < addblobs->blobCount; j++) + { + if (addblobs->blobTab[i].ErrType == blobs->blobTab[j].ErrType && + addblobs->blobTab[i].minx == blobs->blobTab[j].minx && + addblobs->blobTab[i].miny == blobs->blobTab[j].miny && + addblobs->blobTab[i].maxx == blobs->blobTab[j].maxx && + addblobs->blobTab[i].maxy == blobs->blobTab[j].maxy) + { + bhave = 1; + break; + } + } + if (!bhave) + { + int ncount = blobs->blobCount; + if (ncount < _MAX_ERROR_DOT_BLOB) + { + memcpy(&blobs->blobTab[ncount], &addblobs->blobTab[i], sizeof(ERROR_DOTS_BLOB_DATA)); + blobs->blobCount++; + } + } + } + return 0; +} diff --git a/AlgorithmModule/src/CameraCheckAnalysisy.cpp b/AlgorithmModule/src/CameraCheckAnalysisy.cpp new file mode 100644 index 0000000..b2ba43d --- /dev/null +++ b/AlgorithmModule/src/CameraCheckAnalysisy.cpp @@ -0,0 +1,1493 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:50:00 + * @LastEditTime: 2025-09-23 10:29:01 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/src/CamDeal.cpp + */ +#include "CameraCheckAnalysisy.hpp" +#include "CheckUtil.hpp" +#include "Define.h" + +CameraCheckAnalysisy::CameraCheckAnalysisy() +{ + + m_nErrorCode = 0; // 错误代码 + m_bInitSucc = false; // 初始化状态 + m_bExit = false; // 是否退出检测 + m_bHaveImgeDet = false; + m_strcameraName = ""; + nLastCheckAnalysisyThreadIdx = 0; + m_pChannelFuntion = &m_AnalysisyConfig.checkFunction; + m_pbaseCheckFunction = &m_AnalysisyConfig.baseFunction; + m_nConfigIdx = -1; + m_pdetlog = std::make_shared(); + m_pCommonAnalysisyConfig = NULL; + m_imageResultJudge.SetAnalysisyConfig(&m_AnalysisyConfig); + + bshowimg = false; +} + +CameraCheckAnalysisy::~CameraCheckAnalysisy() +{ +} + +int CameraCheckAnalysisy::set_cpu_id(const std::vector &cpu_set_vec) +{ + // for cpu affinity + int nRet = 0; +#ifdef __linux + cpu_set_t _cur_cpu_set; + CPU_ZERO(&_cur_cpu_set); + for (auto _id : cpu_set_vec) + { + CPU_SET(_id, &_cur_cpu_set); + } + if (0 > pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &_cur_cpu_set)) + { + perror("set cpu affinity failed: "); + printf("Warning: set cpu affinity failed ... ...\n"); + nRet = -1; + } +#endif //__linux + return nRet; +} +int CameraCheckAnalysisy::WaitDetImg() +{ + std::unique_lock lk(mtx_WaiteImg); + cond_WaiteImg.wait(lk, [this]() + { return m_bHaveImgeDet; }); + + lk.unlock(); + + return 0; +} + +// 判断物料在左还是在右 +string JudgeMaterialPosition(Mat img) { + if (img.empty() || img.channels() != 1) { + cerr << "Error: Input image is empty or not grayscale!" << endl; + return "Unknown"; + } + resize(img, img, Size(img.cols, img.rows * 0.001), 0, 0); + int rows = img.rows; + int cols = img.cols; + // 统计灰度值 < bg_val 的像素数量 + int left_black_count = 0; + int right_black_count = 0; + int bg_val = 25; + for (int row = 0; row < rows; ++row) { + for (int col = 0; col < 3; ++col) { + if (img.at(row, col) < 25) { + left_black_count++; + } + } + + for (int col = cols - 3; col < cols; ++col) { + if (img.at(row, col) < 25) { + right_black_count++; + } + } + } + // 判断物料位置 + if (left_black_count <= right_black_count) { + return "Left"; + } else if (left_black_count > right_black_count) { + return "Right"; + } +} + +//正常情况CA(img物料在左,img_B物料在右),TA(img物料在右,img_B物料在左) +bool ifExchange(cv::Mat &img, const cv::Mat &img_B, std::string strcam ){ + string img_position = JudgeMaterialPosition(img); + string img_B_position = JudgeMaterialPosition(img_B); + if (strcam == "TA"){ + if (img_position == "Left" && img_B_position == "Right"){ + return true; + } + else{ + return false; + } + } + else{ + if (img_position == "Right" && img_B_position == "Left"){ + return true; + } + else{ + return false; + } + } + +} + +int CameraCheckAnalysisy::Detect_Pre() +{ + + std::string strlog; + std::string strSN; + std::string strBasic; + + strSN = m_pCheck_Result->productBaseResult->strproductName; + strBasic = ">>" + strSN + " cam:" + m_strcameraName; + + m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s ==================start", strBasic.c_str()); + std::shared_ptr pImageResult = m_pCheck_Result->GetNoDetImg(); + + if (!pImageResult) + { + return 1; + } + if (!pImageResult->result->in_shareImage->bCam_AB) + { + m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s ==================bCam_AB = false", strBasic.c_str()); + return 0; + } + if (pImageResult->result->in_shareImage->img.empty() || + pImageResult->result->in_shareImage->img_B.empty()) + { + m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s ==================img.empty() || img_B.empty() ", strBasic.c_str()); + return 1; + } + + //判断图片左右,0为左,1为右 + bool exchange_img = ifExchange(pImageResult->result->in_shareImage->img, pImageResult->result->in_shareImage->img_B, pImageResult->result->in_shareImage->strCameraName); + if(exchange_img){ + std::swap(pImageResult->result->in_shareImage->img, pImageResult->result->in_shareImage->img_B); + } + + // printf("===66666666666666666\n"); + int re = Mergimg(pImageResult->result->in_shareImage->img, pImageResult->result->in_shareImage->img_B, + pImageResult->result->in_shareImage->strCameraName, pImageResult->result->in_shareImage->strChannel); + + if (pImageResult->result->in_shareImage->Det_Mode == DET_MODE_MergeImg) + { + cv::imwrite(pImageResult->result->in_shareImage->strCameraName + "_MergeImg.png", pImageResult->result->in_shareImage->img); + return 2; + } + + return 0; +} + +int CameraCheckAnalysisy::Mergimg(cv::Mat &img, const cv::Mat &img_B, std::string strcam, std::string strchannel) +{ + // std::cout << img.size() << std::endl; + // std::cout << img_B.size() << std::endl; + if (img.size() != img_B.size()) + { + return -1; + } + long t1, t2; + t1 = CheckUtil::getcurTime(); + int re = 0; + cv::Rect Left_Roi; + cv::Rect Right_Roi; + cv::Mat AllImg = cv::Mat::zeros(img.rows, img.cols * 2, img.type()); + // cv::imwrite(strcam + strchannel + "_img.png", img); + // cv::imwrite(strcam + strchannel + "img_B.png", img_B); + if (strcam == "TA") + { + cv::Rect Left_Tem_Roi; + cv::Point Left_Tem_Point_Up; + cv::Point Left_Tem_Point_Donw; + cv::Rect Right_Tem_Roi; + cv::Point Right_Tem_Point_Up; + cv::Point Right_Tem_Point_Donw; + // left Img + + { + re = GetRectAndPoint(img, Left_Tem_Roi, Left_Tem_Point_Up, Left_Tem_Point_Donw, false, strcam, strchannel); + if (re != 0) + { + m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s Mergimg GetRectAndPoint TAA error %d", strcam.c_str(), re); + return 1; + } + re = GetRectAndPoint(img_B, Right_Tem_Roi, Right_Tem_Point_Up, Right_Tem_Point_Donw, true, strcam, strchannel); + if (re != 0) + { + m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s Mergimg GetRectAndPoint TAB error %d", strcam.c_str(), re); + return 1; + } + + img(Left_Tem_Roi).copyTo(AllImg(Left_Tem_Roi)); + + int hlen_left = Left_Tem_Point_Donw.y - Left_Tem_Point_Up.y; + int hlen_right = Right_Tem_Point_Donw.y - Right_Tem_Point_Up.y; + float fhscle = hlen_left * 1.0f / hlen_right; + int dy = Left_Tem_Point_Up.y - Right_Tem_Point_Up.y; + cv::Rect allroi = Right_Tem_Roi; + allroi.height *= fhscle; + allroi.x = Left_Tem_Roi.x + Left_Tem_Roi.width; + allroi.y += dy; + + cv::Size sz; + sz.width = allroi.width; + sz.height = allroi.height; + + cv::resize(img_B(Right_Tem_Roi), AllImg(allroi), sz); + } + } + else + { + cv::Rect Left_Tem_Roi; + cv::Point Left_Tem_Point_Up; + cv::Point Left_Tem_Point_Donw; + cv::Rect Right_Tem_Roi; + cv::Point Right_Tem_Point_Up; + cv::Point Right_Tem_Point_Donw; + // left Img + + { + re = GetRectAndPoint(img_B, Left_Tem_Roi, Left_Tem_Point_Up, Left_Tem_Point_Donw, false, strcam, strchannel); + if (re != 0) + { + m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s Mergimg GetRectAndPoint CAA error %d", strcam.c_str(), re); + return 1; + } + re = GetRectAndPoint(img, Right_Tem_Roi, Right_Tem_Point_Up, Right_Tem_Point_Donw, true, strcam, strchannel); + if (re != 0) + { + m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s Mergimg GetRectAndPoint CAB error %d", strcam.c_str(), re); + return 1; + } + + img_B(Left_Tem_Roi).copyTo(AllImg(Left_Tem_Roi)); + int hlen_left = Left_Tem_Point_Donw.y - Left_Tem_Point_Up.y; + int hlen_right = Right_Tem_Point_Donw.y - Right_Tem_Point_Up.y; + float fhscle = hlen_left * 1.0f / hlen_right; + int dy = Left_Tem_Point_Up.y - Right_Tem_Point_Up.y; + cv::Rect allroi = Right_Tem_Roi; + allroi.height *= fhscle; + allroi.x = Left_Tem_Roi.x + Left_Tem_Roi.width; + allroi.y += dy; + + cv::Size sz; + sz.width = allroi.width; + sz.height = allroi.height; + + cv::resize(img(Right_Tem_Roi), AllImg(allroi), sz); + } + } + img = AllImg; + t2 = CheckUtil::getcurTime(); + // cv::imwrite(strcam + strchannel + "_merg.png", AllImg); + m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s Mergimg use time %ld ms", strcam.c_str(), t2 - t1); + return 0; +} + +int CameraCheckAnalysisy::GetRectAndPoint(const cv::Mat &img, cv::Rect &roi, cv::Point &merg_p_up, cv::Point &merg_p_down, bool bleft, std::string strcam, std::string strchannel) +{ + + bshowimg = false; + + int A_line_up = 0; + int A_line_down = 0; + + Edge_Search_Config config; + + if (bshowimg) + { + if (img.channels() != 1) + { + showimg = img.clone(); + } + else + { + cv::cvtColor(img, showimg, cv::COLOR_GRAY2BGR); + } + } + + config.nSearchCount = 10; + config.strchannel = strchannel; + config.directSign = DirectSign_UP; + if (bleft) + { + config.roi = cv::Rect(0, 0, 200, img.rows * 0.8); + } + else + { + config.roi = cv::Rect(img.cols - 200, 0, 200, img.rows * 0.8); + } + + int re123 = GetEdgePoint(img, &config, A_line_up); + if (re123 != 0) + { + printf("DirectSign_UP::111111111111GetEdgePoint111111 A_line_up %d\n", re123); + return 1; + } + + config.directSign = DirectSign_DOWN; + config.strchannel = strchannel + "ccc"; + config.roi = cv::Rect(0, img.rows * 0.2, 200, img.rows * 0.8 - 1); + + if (bleft) + { + config.roi = cv::Rect(0, img.rows * 0.2, 200, img.rows * 0.8 - 1); + } + else + { + config.roi = cv::Rect(img.cols - 200, img.rows * 0.2, 200, img.rows * 0.8 - 1); + } + + re123 = GetEdgePoint(img, &config, A_line_down); + if (re123 != 0) + { + printf("DirectSign_UP::111111111111GetEdgePoint111111 A_line_down %d\n", re123); + return 1; + } + + { + if (bshowimg) + { + cv::line(showimg, cv::Point(0, A_line_down), cv::Point(img.cols, A_line_down), cv::Scalar(0, 255, 0), 2); + cv::line(showimg, cv::Point(0, A_line_up), cv::Point(img.cols, A_line_up), cv::Scalar(0, 255, 0), 2); + + cv::imwrite(strcam + strchannel + "_line.png", showimg); + } + } + // printf("DirectSign_UP::111111111111111111 re123 %d\n", re123); + // getchar(); + + cv::Mat small, smallbin; + cv::resize(img, small, cv::Size(600, 1500)); + + cv::threshold(small, smallbin, 15, 255, + cv::THRESH_BINARY); + + /* 3. contours */ + std::vector> contours; + cv::findContours(smallbin, contours, + cv::RETR_EXTERNAL, + cv::CHAIN_APPROX_SIMPLE); + + if (contours.empty()) + return 1; + + /* 4. max contour */ + double maxArea = 0; + int idx = -1; + for (int i = 0; i < contours.size(); i++) + { + double area = cv::contourArea(contours[i]); + if (area > maxArea) + { + maxArea = area; + idx = i; + } + } + + if (idx < 0) + return 1; + + cv::Rect rSmall = cv::boundingRect(contours[idx]); + + /* 5. map to original */ + float sx = (float)img.cols / smallbin.cols; + float sy = (float)img.rows / smallbin.rows; + cv::Rect rectInSrc; + + rectInSrc.x = int(rSmall.x * sx) - 50; + rectInSrc.y = int(rSmall.y * sy) - 50; + rectInSrc.width = int(rSmall.width * sx) + 100; + rectInSrc.height = int(rSmall.height * sy) + 100; + + if (rectInSrc.y >= A_line_up) + { + rectInSrc.y = A_line_up - 5; + } + if (rectInSrc.y + rectInSrc.height <= A_line_down) + { + rectInSrc.height = A_line_down + 5 - rectInSrc.y; + } + + if (rectInSrc.x < 0) + rectInSrc.x = 0; + if (rectInSrc.y < 0) + rectInSrc.y = 0; + if (rectInSrc.x + rectInSrc.width > img.cols) + rectInSrc.width = img.cols - rectInSrc.x; + if (rectInSrc.y + rectInSrc.height > img.rows) + { + rectInSrc.height = img.rows - rectInSrc.y; + } + + merg_p_up.y = A_line_up; + merg_p_up.x = img.cols; + merg_p_down.y = A_line_down; + merg_p_down.x = img.cols; + roi = rectInSrc; + + if (bshowimg) + { + cv::rectangle(showimg, rectInSrc, cv::Scalar(0, 0, 255), 2); + cv::imwrite(strcam + strchannel + "_rect.png", showimg); + } + + return 0; +} + +// 对该相机下的每一张图片进行处理 +int CameraCheckAnalysisy::Detect_Images() +{ + + std::string strlog; + std::string strSN; + std::string strBasic; + + strSN = m_pCheck_Result->productBaseResult->strproductName; + strBasic = ">>" + strSN + " cam:" + m_strcameraName; + + m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Images", "Cam %s ==================start", strBasic.c_str()); + // // 循环处理每个图片 + bool bcomplete = false; + long time_No_CheckAnalysisy = 30 * 1000; + long ts = CheckUtil::getcurTime(); + while (!bcomplete) + { + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + ImgCheckBase *pImgCheckAnalysisy = NULL; + long t1 = CheckUtil::getcurTime(); + + // 拿到计算资源 + while (true) + { + + pImgCheckAnalysisy = GetDealResult(-1); + if (pImgCheckAnalysisy != NULL) + { + break; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(20)); // + long t2 = CheckUtil::getcurTime(); + // 如果 超过秒XX都没有拿到处理资源,则直接退出 + if (t2 - t1 > time_No_CheckAnalysisy) + { + m_pdetlog->AddCheckstr(PrintLevel_2, "Detect_Images", "Error %ld ms No pImgCheckAnalysisy", time_No_CheckAnalysisy); + break; + } + } + + // 没有分析检测资源,直接退出 + if (pImgCheckAnalysisy == NULL) + { + continue; + } + // 1、把每张图都进行AI 推理 获得 blob 结果 + std::shared_ptr pImageResult = m_pCheck_Result->GetNoDetImg(); + bool bHaveNotdetImg = false; + // 没有未检测的图片了。 + if (pImageResult) + { + m_pdetlog->AddCheckstr(PrintLevel_2, "Detect_Images", "channel %s send det ", pImageResult->strChannel.c_str()); + bHaveNotdetImg = true; + pImgCheckAnalysisy->SetDataRun_SharePtr(pImageResult); + } + else + { + // 图片都已经送完了。 + if (m_pCheck_Result->getImgPushComplate()) + { + // printf("Cam Detect_Images %s ==================send end \n", strBasic.c_str()); + // 没有图在进行 检测了。 + bool bhavedet = false; + for (int i = 0; i < IMGCHECKANALYSISY_NUM; i++) + { + if (CHECK_THREAD_STATUS_IDLE != m_pImgCheckAnalysisy[i]->GetStatus()) + { + bhavedet = true; + break; + } + } + // printf("Cam Detect_Images %s ==================bhavedet %d\n", strBasic.c_str(), bhavedet); + if (!bhavedet) + { + bcomplete = true; + } + } + else + { + // printf("Cam Detect_Images %s ==================No send end\n", strBasic.c_str() ); + } + } + } + long te = CheckUtil::getcurTime(); + m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Images", "Cam %s =====ALL image det complate time %ld ms=============End", strBasic.c_str(), te - ts); + return 0; +} + +int CameraCheckAnalysisy::ResultParamJudge() +{ + //================================================== + //======= 适用于 单相机或多相机,每个相机之间的图相互没关系。 + //======= + //======= + //======= + //================================================== + + std::string strlog; + std::string strSN; + std::string strBasic; + long ts = CheckUtil::getcurTime(); + + int ImageNum = m_pCheck_Result->ImageALLDetResultList.size(); + if (ImageNum <= 0) + { + m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "Error ImageNum <=0"); + return 1; + } + + // 如果 参数是空,直接返回。 + if (m_pCommonAnalysisyConfig == NULL) + { + m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "Error m_pCommonAnalysisyConfig == NULL"); + return 1; + } + int regionNum = m_pCommonAnalysisyConfig->regionConfigArr.size(); + if (regionNum <= 0) + { + m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "Error Config region num = 0"); + } + + m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "==================start image Num %d region num %d", ImageNum, regionNum); + + // 对每个图片通道进行单独分析 + for (int imgidx = 0; imgidx < ImageNum; imgidx++) + { + long t1 = CheckUtil::getcurTime(); + int re = m_imageResultJudge.ResultJudge(m_pCheck_Result->ImageALLDetResultList.at(imgidx)); + long t2 = CheckUtil::getcurTime(); + m_imageResultJudge.DrawResult(m_pCheck_Result->ImageALLDetResultList.at(imgidx)); + long t3 = CheckUtil::getcurTime(); + m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", " det time %ld ms judge %ld draw %ld", t3 - t1, t2 - t1, t3 - t2); + + // 把结果转成 json 保存。 用以复测 + std::shared_ptr m_CheckResult_shareP = m_pCheck_Result->ImageALLDetResultList.at(imgidx)->result; + m_CheckResult_shareP->strResultJson = m_CheckResultJson.GetResultString(m_pCheck_Result->ImageALLDetResultList.at(imgidx)->pDetResult); + } + long te = CheckUtil::getcurTime(); + m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "==================End time %ld ms ", te - ts); + + // m_pdetlog->printLog(m_strcameraName); + + return 0; +} +int CameraCheckAnalysisy::Init(std::string strcameraName) +{ + m_strcameraName = strcameraName; + printf("CameraCheckAnalysisy::Init start \n"); + SetNewConfig(); + + int re = 0; + re = InitCheckAnalysisy(); + if (CHECK_OK != re) + { + printf("InitCheckAnalysisy error\n"); + return -1; + } + + re = InitRun(); + if (CHECK_OK != re) + { + printf("InitRun error\n"); + m_nErrorCode = re; + return m_nErrorCode; + } + + printf("CameraCheckAnalysisy::Init end \n"); + return 0; +} + +int CameraCheckAnalysisy::StartCheck(std::shared_ptr pCamera_Check_Result) +{ + if (m_bHaveImgeDet) + { + return -1; + } + { + std::lock_guard lock(mtx_WaiteImg); + m_pCheck_Result = pCamera_Check_Result; + if (m_pCheck_Result->bJson) + { + // 如果是 复测 直接进入 参数判断阶段。 + m_pCheck_Result->SetCheckStep(Check_Step_ResultParamJudg); // 进入预处理阶段 + } + else + { + m_pCheck_Result->SetCheckStep(Check_Step_PreDet); // 进入预处理阶段 + } + + m_bHaveImgeDet = true; + m_pdetlog = m_pCheck_Result->detlog; + m_pdetlog->AddCheckstr(PrintLevel_0, "StartCheck", "==================start %s", m_pCheck_Result->cameraBaseResult->strCameraName.c_str()); + } + cond_WaiteImg.notify_all(); + return 0; +} +int CameraCheckAnalysisy::StartThread() +{ + m_bExit = false; + // 开启检测线程 + ptr_thread_Run = std::make_shared(std::bind(&CameraCheckAnalysisy::Run, this)); + return 0; +} +int CameraCheckAnalysisy::StopThread() +{ + m_bExit = true; + if (ptr_thread_Run != nullptr) + { + if (ptr_thread_Run->joinable()) + { + ptr_thread_Run->join(); + } + } + return 0; +} +int CameraCheckAnalysisy::InitRun() +{ + int re; + re = StartThread(); + if (CHECK_OK != re) + { + return re; + } + m_bInitSucc = true; + // 检测前更新参数 + SetNewConfig(); + return 0; +} +int CameraCheckAnalysisy::InitCheckAnalysisy() +{ + int re = 0; + for (int i = 0; i < IMGCHECKANALYSISY_NUM; i++) + { + RunInfoST RunConfig; + RunConfig.nThreadIdx = i; + + m_pImgCheckAnalysisy[i] = ImgCheckBase::GetInstance(); + re = m_pImgCheckAnalysisy[i]->UpdateConfig((void *)&RunConfig, CHECK_CONFIG_Run); + if (re != 0) + { + printf("UpdateConfig %d Fail %s\n", CHECK_CONFIG_Run, m_pImgCheckAnalysisy[i]->GetErrorInfo().c_str()); + return re; + } + re = m_pImgCheckAnalysisy[i]->UpdateConfig((void *)m_pConfig.get(), CHECK_CONFIG_Module); + if (re != 0) + { + printf("UpdateConfig %d Fail %s\n", CHECK_CONFIG_Module, m_pImgCheckAnalysisy[i]->GetErrorInfo().c_str()); + return re; + } + + re = m_pImgCheckAnalysisy[i]->RunStart(); + if (re != 0) + { + printf("cami %s RunStart Fail ==%d\n", m_strcameraName.c_str(), re); + return re; + } + // printf(">>>>cami %s InitCheckAnalysisy: ImgCheckThread %d / %d Start Succ \n", m_strcameraName.c_str(), i+1, IMGCHECKANALYSISY_NUM); + + if (re != 0) + { + return re; + } + } + return 0; +} +int CameraCheckAnalysisy::CheckImgRun() +{ + + int re = 0; + Check_Step curcheckStep = m_pCheck_Result->GetCheckStep(); + m_pdetlog->bPrintStr = false; + m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "------------curcheckStep:%d ", curcheckStep); + // 如果是未检测状态,则开始预处理 + if (curcheckStep == Check_Step_NODet) + { + m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "Error curcheckStep = NODet "); + return 1; + } + // 检测前更新参数 + SetNewConfig(); + // 预处理 + if (curcheckStep == Check_Step_PreDet) + { + m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_PreDet", m_pCheck_Result->cameraBaseResult->strCameraName.c_str()); + re = Detect_Pre(); + if (re != 0) + { + m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_PreDet error = %d", m_pCheck_Result->cameraBaseResult->strCameraName.c_str(), re); + curcheckStep = Check_Step_ImgeDet_End; // 进入到预图片检测阶段 + } + else + { + curcheckStep = Check_Step_ImgeDet; // 进入到预图片检测阶段 + } + + m_pCheck_Result->SetCheckStep(curcheckStep); + } + + // 检测每张图片 + if (curcheckStep == Check_Step_ImgeDet) + { + m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_ImgeDet", m_pCheck_Result->cameraBaseResult->strCameraName.c_str()); + // 检测每张图片 + re = Detect_Images(); + curcheckStep = Check_Step_ResultParamJudg; // 进入到预图片检测阶段 + m_pCheck_Result->SetCheckStep(curcheckStep); + } + + // 对检测结果进行参数判断,判断是否NG. + if (curcheckStep == Check_Step_ResultParamJudg) + { + m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_ResultParamJudg", m_pCheck_Result->cameraBaseResult->strCameraName.c_str()); + // 检测每张图片 + re = ResultParamJudge(); + // 如果有异常 + if (re != 0) + { + // 图片 送图没有完成,则继续等待。 + if (!m_pCheck_Result->getImgPushComplate()) + { + return 1; + } + } + + curcheckStep = Check_Step_ImgeDet_End; // 进入到预图片检测阶段 + m_pCheck_Result->SetCheckStep(curcheckStep); + } + + if (curcheckStep == Check_Step_ImgeDet_End) + { + m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_ImgeDet_End", m_pCheck_Result->cameraBaseResult->strCameraName.c_str()); + + // 所有图片都送完了。 + if (m_pCheck_Result->getImgPushComplate()) + { + curcheckStep = Check_Step_Complete; // 进入到预图片检测阶段 + m_pCheck_Result->SetCheckStep(curcheckStep); + } + else + { + printf("========came %s wait img send end \n", m_strcameraName.c_str()); + } + } + + // 检测完成, + if (curcheckStep == Check_Step_Complete) + { + long tend = CheckUtil::getcurTime(); + m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_Complete", m_pCheck_Result->cameraBaseResult->strCameraName.c_str()); + std::string strTimg = CheckUtil::getCurTimeHMS(); + m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "========came %s Check ALL end time %ld ms %s", + m_pCheck_Result->cameraBaseResult->strCameraName.c_str(), tend - m_pCheck_Result->time_start, strTimg.c_str()); + InsertCameraLog(); + std::lock_guard lock(mtx_WaiteImg); + m_bHaveImgeDet = false; + + m_pCheck_Result.reset(); + } + // m_pdetlog->printLog(m_strcameraName); + return 0; +} + +int CameraCheckAnalysisy::Run() +{ + + while (!m_bExit) + { + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + WaitDetImg(); + int re = CheckImgRun(); + } + + return 0; +} + +int CameraCheckAnalysisy::ImgEdge(cv::Mat img, cv::Mat &detMaskImg, cv::Rect &roi, int productIdx) +{ + int re = 0; + + return re; +} + +int CameraCheckAnalysisy::InsertCameraLog() +{ + + int ImageNum = m_pCheck_Result->ImageALLDetResultList.size(); + for (int imgidx = 0; imgidx < ImageNum; imgidx++) + { + + std::shared_ptr pImageResult = m_pCheck_Result->ImageALLDetResultList.at(imgidx); + std::shared_ptr m_CheckResult_shareP = pImageResult->result; // 返回结果 + if (!m_CheckResult_shareP || !pImageResult) + { + continue; + } + + // 1、把图片的相关日志 写到 返回 日志中。 + m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), + pImageResult->detlog->logList.begin(), pImageResult->detlog->logList.end()); + std::string str = ""; + char buffer[256]; + // 2、把缺陷信息 写的 返回日志中。 + { + + std::shared_ptr pDetResult = pImageResult->pDetResult; // 检测结果 + if (!pDetResult) + { + continue; + } + if (!pDetResult->pQx_ErrorList) + { + continue; + } + int qxNum = pDetResult->pQx_ErrorList->size(); + + // Add NG log + + { + sprintf(buffer, " =====================NG num %d=============================", pImageResult->NG_num); + str = buffer; + m_CheckResult_shareP->det_LogList.push_back(str); + } + for (int qxidx = 0; qxidx < qxNum; qxidx++) + { + QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx); + + if (QX_info->result == QX_RESULT_TYPE_NG) + { + std::shared_ptr pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog; + m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), + pQxLog->logList.begin(), pQxLog->logList.end()); + } + } + + { + sprintf(buffer, " =====================YS num %d=============================", pImageResult->YS_num); + str = buffer; + m_CheckResult_shareP->det_LogList.push_back(str); + } + for (int qxidx = 0; qxidx < qxNum; qxidx++) + { + QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx); + + if (QX_info->result == QX_RESULT_TYPE_YS) + { + std::shared_ptr pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog; + m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), + pQxLog->logList.begin(), pQxLog->logList.end()); + } + } + + { + sprintf(buffer, " =====================OK num %d=============================", pImageResult->Ok_num); + str = buffer; + m_CheckResult_shareP->det_LogList.push_back(str); + } + for (int qxidx = 0; qxidx < qxNum; qxidx++) + { + QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx); + + if (QX_info->result == QX_RESULT_TYPE_OK) + { + std::shared_ptr pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog; + m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), + pQxLog->logList.begin(), pQxLog->logList.end()); + } + } + + { + sprintf(buffer, " =====================NO Judge num %d=============================", pImageResult->NoJudge_num); + str = buffer; + m_CheckResult_shareP->det_LogList.push_back(str); + } + for (int qxidx = 0; qxidx < qxNum; qxidx++) + { + QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx); + + if (QX_info->result == QX_RESULT_TYPE_NoJduge) + { + std::shared_ptr pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog; + m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), + pQxLog->logList.begin(), pQxLog->logList.end()); + } + } + } + + { + sprintf(buffer, " =====================Cam Log ============================="); + str = buffer; + m_CheckResult_shareP->det_LogList.push_back(str); + } + + // 3、把相机的日志 写到 返回日志中。 + m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), + m_pCheck_Result->detlog->logList.begin(), m_pCheck_Result->detlog->logList.end()); + + { + sprintf(buffer, " =====================Product Log ============================="); + str = buffer; + m_CheckResult_shareP->det_LogList.push_back(str); + } + // 4、把产品相关日志 写到 返回日志中。 + m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), + m_pCheck_Result->productBaseResult->detlog->logList.begin(), m_pCheck_Result->productBaseResult->detlog->logList.end()); + } + return 0; +} +ChannelCheckFunction *CameraCheckAnalysisy::GetChannelFuntion(std::string strChannelName) +{ + ChannelCheckFunction *p = NULL; + // printf("m_pChannelFuntion->channelFunctionArr.size() %zu\n", m_pChannelFuntion->channelFunctionArr.size()); + for (int i = 0; i < m_pChannelFuntion->channelFunctionArr.size(); i++) + { + if (CheckUtil::compareIgnoreCase(m_pChannelFuntion->channelFunctionArr[i].strChannelName, strChannelName)) + { + p = &m_pChannelFuntion->channelFunctionArr[i]; + } + } + + return p; +} +int CameraCheckAnalysisy::SetNewConfig() +{ + + if (m_pConfig.get() == nullptr) + { + return 1; + } + if (m_nConfigIdx < 0) + { + m_nConfigIdx = m_pConfig->GetConfigIdx(); + m_pdetlog->AddCheckstr(PrintLevel_1, "update config", "CameraCheckAnalysisy:%s m_nConfigIdx %d", m_strcameraName.c_str(), m_nConfigIdx); + } + + if (m_pConfig->GetConfigUpdataStatus(ConfigType_Analysisy_Common_XL, m_nConfigIdx)) + { + m_pConfig->GetConfig(ConfigType_Analysisy_Common_XL, &m_AnalysisyConfig); + if (m_AnalysisyConfig.commonCheckConfig.nodeConfigArr.size() > 0) + { + m_pCommonAnalysisyConfig = &m_AnalysisyConfig.commonCheckConfig.nodeConfigArr.at(0); + m_imageResultJudge.UpdateConfig(); + } + else + { + m_pCommonAnalysisyConfig = NULL; + printf("m_AnalysisyConfig.commonCheckConfig.nodeConfigArr == 0 \n"); + } + m_pdetlog->AddCheckstr(PrintLevel_1, "update config", "Get New analysisy config"); + // printf("*******ALLImgCheckAnalysisy m_pConfig*********************** Update GetConfig \n"); + // m_AnalysisyConfig.checkFunction.print("Update GetConfig"); + } + + return 0; +} + +int CameraCheckAnalysisy::preDet_ZF(std::shared_ptr p, std::shared_ptr &pResult) +{ + ImgCheckBase *pImgCheckAnalysisy = NULL; + long t1 = CheckUtil::getcurTime(); + int outTime = 1000 * 5; + while (true) + { + + pImgCheckAnalysisy = GetDealResult(-1); + if (pImgCheckAnalysisy != NULL) + { + break; + } + long t2 = CheckUtil::getcurTime(); + // 超时 + if (t2 - t1 > outTime) + { + return 1; + } + std::this_thread::sleep_for(std::chrono::milliseconds(20)); // 模拟消费过程 + } + p->pBaseImgCheckConfig->imgtype = 1; + pImgCheckAnalysisy->CheckImg(p, pResult); + p->pBaseImgCheckConfig->imgtype = 0; + return 0; +} + +ImgCheckBase *CameraCheckAnalysisy::GetDealResult(int idx) +{ + + // 特殊情况 + if (idx >= 0 && idx < IMGCHECKANALYSISY_NUM) + { + + if (CHECK_THREAD_STATUS_IDLE == m_pImgCheckAnalysisy[idx]->GetStatus()) + { + // printf("*-*-*-*-*-*-*-*- use m_pImgCheckAnalysisy %d \n", idx); + return m_pImgCheckAnalysisy[idx]; + } + else + { + return NULL; + } + } + + int re = 0; + + int nidx = nLastCheckAnalysisyThreadIdx; + + for (int i = 0; i < IMGCHECKANALYSISY_NUM; i++) + { + if (nidx >= IMGCHECKANALYSISY_NUM) + { + nidx = 0; + } + if (CHECK_THREAD_STATUS_IDLE == m_pImgCheckAnalysisy[nidx]->GetStatus()) + { + nLastCheckAnalysisyThreadIdx = nidx + 1; + // printf("*-*-*-*-*-*-*-*- use m_pImgCheckAnalysisy %d \n", nidx); + return m_pImgCheckAnalysisy[nidx]; + } + nidx++; + } + return NULL; +} + +int CameraCheckAnalysisy::GetEdgePoint(const cv::Mat &img, Edge_Search_Config *pEdge_Search_Config, int &outP) +{ + bool bdbuge = false; + bdbuge = bshowimg; + if (img.empty()) + { + return -11; + } + if (img.channels() != 1) + { + // printf("*****************************channels\n"); + + return -12; + } + // 检查roi; + if (!CheckUtil::RoiInImg(pEdge_Search_Config->roi, img)) + { + return -13; + } + if (!pEdge_Search_Config->CheckConfigValid()) + { + return -14; + } + std::vector pointList; + bool search_UP_DOWN = false; + cv::Rect roi = pEdge_Search_Config->roi; + int sx = roi.x; + int ex = roi.x + roi.width; + int sy = roi.y; + int ey = roi.y + roi.height; + + int nSearchLen = roi.width; // 搜索区域的长度 + int nCurPoint_Step = pEdge_Search_Config->stepCount; // 当前点搜索的步长 + + // 搜索小范围确认 + int nhalfrang = (int)pEdge_Search_Config->nSearchrange / 2; + int nrange_start = 0 - nhalfrang; + int nrange_end = 0 - nhalfrang; + int num = 0; + while (true) + { + num++; + nrange_end++; + if (num >= pEdge_Search_Config->nSearchrange) + { + break; + } + } + // 判断方向 + switch (pEdge_Search_Config->directSign) + { + case DirectSign_UP: + search_UP_DOWN = true; + nSearchLen = roi.width; + sx = roi.x; + ex = roi.x + roi.width; + sy = roi.y; + ey = roi.y + roi.height; + nCurPoint_Step = pEdge_Search_Config->stepCount; + break; + case DirectSign_DOWN: + search_UP_DOWN = true; + nSearchLen = roi.width; + nCurPoint_Step = -pEdge_Search_Config->stepCount; + + sx = roi.x; + ex = roi.x + roi.width; + sy = roi.y + roi.height - 1; + ey = roi.y; + break; + case DirectSign_Left: + nSearchLen = roi.height; + search_UP_DOWN = false; + nCurPoint_Step = pEdge_Search_Config->stepCount; + + sx = roi.x; + ex = roi.x + roi.width; + sy = roi.y; + ey = roi.y + roi.height; + break; + case DirectSign_Right: + nSearchLen = roi.height; + search_UP_DOWN = false; + nCurPoint_Step = -pEdge_Search_Config->stepCount; + + sx = roi.x + roi.width - 1; + ex = roi.x; + sy = roi.y; + ey = roi.y + roi.height; + break; + default: + break; + } + + // 搜索 点数 + int nSearchPointNum = pEdge_Search_Config->nSearchCount; + // 搜素点的间隔 + int nSearchPointStep = 1; + if (nSearchPointNum > 1) + { + nSearchPointStep = int(nSearchLen * 1.0f / (nSearchPointNum - 1)); + } + + if (bdbuge) + { + cv::rectangle(showimg, roi, cv::Scalar(255, 0, 0), 2); + printf("nSearchPointStep %d nCurPoint_Step %d,nrange_start %d %d\n", nSearchPointStep, nCurPoint_Step, nrange_start, nrange_end); + } + + uchar *pdata = (uchar *)img.data; + int offt = 0; + // 搜索 上下边 + if (search_UP_DOWN) + { + // 每个搜索点 分布在X方向。 + for (int x = sx; x < ex; x = x + nSearchPointStep) + { + int bOKNum = 0; + int cur_x = x; + int cur_y = sy; + bool bSucc = false; + int succ_y = 0; + + // 对每个搜索点进行 y方向搜索 + for (int y = sy;; y = y + nCurPoint_Step) + { + + if (y < 0 || y >= img.rows) + { + continue; + } + + // + if (nCurPoint_Step > 0 && y > ey) + { + break; + } + if (nCurPoint_Step < 0 && y < ey) + { + break; + } + offt = y * img.cols; + int range_okNum = 0; + // 对一定范围的点进行判断 + for (int k = nrange_start; k < nrange_end; k++) + { + int rangeX = x + k; + if (rangeX < 0 || rangeX >= img.cols) + { + continue; + } + offt += rangeX; + if (offt < 0 || offt >= img.cols * img.rows) + { + printf("rangeX %d nCurPoint_Step %d off %d x %d y %d sy %d ey %d %d %d\n", rangeX, nCurPoint_Step, offt, x, y, sy, ey, img.cols, img.rows); + } + + if (pdata[offt] >= pEdge_Search_Config->nValueThreshold) // 找到 + { + range_okNum++; + } + } + if (range_okNum >= pEdge_Search_Config->nSearchrange) + { + if (bdbuge) + { + cv::circle(showimg, cv::Point(x, y), 1, cv::Scalar(0, 0, 255)); + } + if (bOKNum == 0) + { + cur_y = y; + } + + bOKNum++; + + // 连续搜索到 满足要求的点。 + if (bOKNum >= pEdge_Search_Config->nLimit) + { + bSucc = true; + succ_y = y; + break; + } + } + else + { + // 如果有间断,需要重新计算连续情况。 + bOKNum = 0; + if (bdbuge) + { + cv::circle(showimg, cv::Point(x, y), 1, cv::Scalar(0, 255, 0)); + } + } + } + if (bSucc) + { + cv::Point p(cur_x, cur_y); + if (bdbuge) + { + cv::circle(showimg, p, 3, cv::Scalar(255, 0, 0)); + } + pointList.push_back(p); + + if (pointList.size() > 5) + { + // printf("=============feeeee\n"); + sy = succ_y - 100; + ey = succ_y + 100; + if (sy < 0) + { + sy = 0; + } + if (ey >= img.rows) + { + ey = img.rows - 1; + } + } + } + } + } + else // 搜索 左右边 + { + // 每个搜索点 分布在X方向。 + for (int y = sy; y < ey; y = y + nSearchPointStep) + { + int bOKNum = 0; + int cur_x = sx; + int cur_y = y; + bool bSucc = false; + int succ_x = 0; + + // 对每个搜索点进行 y方向搜索 + for (int x = sx;; x = x + nCurPoint_Step) + { + if (x < 0 || x >= img.cols) + { + continue; + } + // + if (nCurPoint_Step > 0 && x > ex) + { + break; + } + if (nCurPoint_Step < 0 && x < ex) + { + break; + } + + int range_okNum = 0; + // 对一定范围的点进行判断 + for (int k = nrange_start; k < nrange_end; k++) + { + int rangey = y + k; + if (rangey < 0 || rangey >= img.rows) + { + continue; + } + offt = rangey * img.cols + x; + if (offt < 0 || offt >= img.cols * img.rows) + { + printf("rangey %d off %d x %d y %d ey %d %d %d\n", rangey, offt, x, y, ey, img.cols, img.rows); + } + if (pdata[offt] >= pEdge_Search_Config->nValueThreshold) // 找到 + { + range_okNum++; + } + } + if (range_okNum >= pEdge_Search_Config->nSearchrange) + { + if (bdbuge) + { + cv::circle(showimg, cv::Point(x, y), 1, cv::Scalar(0, 0, 255)); + } + if (bOKNum == 0) + { + cur_x = x; + } + + bOKNum++; + // 连续搜索到 满足要求的点。 + if (bOKNum >= pEdge_Search_Config->nLimit) + { + bSucc = true; + succ_x = x; + break; + } + } + else + { + // 如果有间断,需要重新计算连续情况。 + bOKNum = 0; + if (bdbuge) + { + cv::circle(showimg, cv::Point(x, y), 1, cv::Scalar(0, 255, 0)); + } + } + } + if (bSucc) + { + cv::Point p(cur_x, cur_y); + if (bdbuge) + { + cv::circle(showimg, p, 3, cv::Scalar(255, 0, 0)); + } + pointList.push_back(p); + if (pointList.size() > 5) + { + // printf("=============feeeee\n"); + sx = succ_x - 100; + ex = succ_x + 100; + if (sx < 0) + { + sx = 0; + } + if (ex >= img.cols) + { + ex = img.cols - 1; + } + } + } + } + } + + if (bdbuge) + { + cv::imwrite(pEdge_Search_Config->strchannel + "show.png", showimg); + } + + { + const int maxDeviation = 10; // 可调阈值:最大允许偏离像素 + + std::vector avgPoints; + + int PNum = pointList.size(); + // 第一次计算粗略均值 + int sum_y = 0, sum_x = 0; + for (const auto &pt : pointList) + { + + sum_x += pt.x; + sum_y += pt.y; + } + float avg_y = sum_y * 1.0f / PNum; + float avg_x = sum_x * 1.0f / PNum; + + // 过滤异常点 + std::vector filtered; + for (const auto &pt : pointList) + { + if (search_UP_DOWN) // 横向:判断 y 偏差 + { + + if (std::abs(pt.y - avg_y) <= maxDeviation) + filtered.push_back(pt); + } + else // 纵向:判断 x 偏差 + { + if (std::abs(pt.x - avg_x) <= maxDeviation) + filtered.push_back(pt); + } + } + + if (filtered.empty()) + return -1; + + int sum_fx = 0, sum_fy = 0; + for (const auto &pt : filtered) + { + sum_fx += pt.x; + sum_fy += pt.y; + } + + if (search_UP_DOWN) // 横向:判断 y 偏差 + { + outP = sum_fy / (int)filtered.size(); + } + else // 纵向:判断 x 偏差 + { + outP = sum_fx / (int)filtered.size(); + } + } + + return 0; +} + +int CameraCheckAnalysisy::GetLine(const cv::Mat &img, std::vector &pointList, int lineNum, int xory, int &outP) +{ + + if (pointList.size() < 0) + return -1; + + const int maxDeviation = 10; // 可调阈值:最大允许偏离像素 + + std::vector avgPoints; + + int PNum = pointList.size(); + // 第一次计算粗略均值 + int sum_y = 0, sum_x = 0; + for (const auto &pt : pointList) + { + + sum_x += pt.x; + sum_y += pt.y; + } + float avg_y = sum_y * 1.0f / PNum; + float avg_x = sum_x * 1.0f / PNum; + + // 过滤异常点 + std::vector filtered; + for (const auto &pt : pointList) + { + if (xory == 0) // 横向:判断 y 偏差 + { + if (std::abs(pt.y - avg_y) <= maxDeviation) + filtered.push_back(pt); + } + else // 纵向:判断 x 偏差 + { + if (std::abs(pt.x - avg_x) <= maxDeviation) + filtered.push_back(pt); + } + } + if (filtered.empty()) + return -1; + + int sum_fx = 0, sum_fy = 0; + for (const auto &pt : filtered) + { + sum_fx += pt.x; + sum_fy += pt.y; + } + + if (xory == 0) // 横向:判断 y 偏差 + { + outP = sum_fy / (int)filtered.size(); + } + else // 纵向:判断 x 偏差 + { + outP = sum_fx / (int)filtered.size(); + } + + return 0; +} diff --git a/AlgorithmModule/src/CameraResult.cpp b/AlgorithmModule/src/CameraResult.cpp new file mode 100644 index 0000000..02a974f --- /dev/null +++ b/AlgorithmModule/src/CameraResult.cpp @@ -0,0 +1,110 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-09-13 20:39:37 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-17 16:39:47 + * @FilePath: /BOE_CELL_AOI_Detect/AlgorithmModule/src/CameraResult.cpp + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#include "CameraResult.h" + +CameraResult::CameraResult() +{ + cameraBaseResult = std::make_shared(); + detlog = std::make_shared(); + time_start = 0; +} + +CameraResult::~CameraResult() +{ +} + +void CameraResult::AddLog(std::string str) +{ + LogList.push_back(str); +} + +int CameraResult::AddDetImage(std::shared_ptr p) +{ + if (time_start == 0) + { + time_start = CheckUtil::getcurTime(); + /* code */ + } + + std::shared_ptr imgResult = std::make_shared(); + imgResult->cameraBaseResult = cameraBaseResult; + imgResult->productBaseResult = productBaseResult; + if (p->Det_Mode == DET_MODE_ReJson) + { + bJson = true; + } + + imgResult->AddDetImage(p); + + { + std::lock_guard lock_cam(mtx_DetImageList); + ImageALLDetResultList.push_back(imgResult); + } + { + std::lock_guard lock_cam(mtx_Det); + cameraImage_Status.bHaveImg = true; + cameraImage_Status.bHave_L255 = true; + } + std::string strTimg = CheckUtil::getCurTimeHMS(); + + detlog->AddCheckstr(PrintLevel_0, "PushInImg", " product %s Cam %s add new image channel = %s %s", + productBaseResult->strproductName.c_str(), + cameraBaseResult->strCameraName.c_str(), imgResult->strChannel.c_str(), strTimg.c_str()); + return 0; +} + +bool CameraResult::bCheckCamplate() +{ + std::lock_guard lock_cam(mtx_Det); + + if (checkStep == Check_Step_Complete) + { + return true; + } + + return false; +} + +Check_Step CameraResult::GetCheckStep() +{ + std::lock_guard lock_cam(mtx_Det); + return checkStep; +} + +void CameraResult::SetCheckStep(Check_Step step) +{ + std::lock_guard lock_cam(mtx_Det); + checkStep = step; +} + +bool CameraResult::getImgPushComplate() +{ + std::lock_guard lock_cam(mtx_Det); + return bIsImgComplete; +} + +void CameraResult::setImgPushComplate() +{ + std::lock_guard lock_cam(mtx_Det); + bIsImgComplete = true; +} + +std::shared_ptr CameraResult::GetNoDetImg() +{ + std::lock_guard lock_cam(mtx_DetImageList); + for (auto ptr : ImageALLDetResultList) + { + if (ptr->IsNotDet()) + { + return ptr; + } + } + + return nullptr; +} diff --git a/AlgorithmModule/src/CheckErrorCodeDefine.cpp b/AlgorithmModule/src/CheckErrorCodeDefine.cpp new file mode 100644 index 0000000..09c87c4 --- /dev/null +++ b/AlgorithmModule/src/CheckErrorCodeDefine.cpp @@ -0,0 +1,35 @@ +#include "CheckErrorCodeDefine.hpp" +std::string GetErrorCodeInfo(int nErrorCode) +{ + std::string str = ""; + switch (nErrorCode) + { + case CHECK_OK: + str = "OK"; + break; + case CHECK_ERROR_VERSION: + str = "interface version or config version error"; + break; + case CHECK_ERROR_Config_Null: + str = "prt* config is null"; + break; + case CHECK_ERROR_Config_Value: + str = "config value error"; + break; + case CHECK_ERROR_Path_NULL: + str = "file Path is Null"; + break; + case CHECK_ERROR_Mask_Empty: + str = "mask Image is empty"; + break; + case CHECK_ERROR_Config_cutRoi: + str = "config Rect Value error"; + break; + case CHECK_ERROR_CheckImg_Empty: + str = "check image is empty"; + break; + default: + break; + } + return str; +} diff --git a/AlgorithmModule/src/CheckResultJson.cpp b/AlgorithmModule/src/CheckResultJson.cpp new file mode 100644 index 0000000..3ffd12d --- /dev/null +++ b/AlgorithmModule/src/CheckResultJson.cpp @@ -0,0 +1,169 @@ +#include "CheckResultJson.h" + +Json::Value CheckResultJson::toJsonValue() +{ + Json::Value root; + + { + + root["cutRoi"]["x"] = m_pOneImgDetResult->CutRoi.x; + root["cutRoi"]["y"] = m_pOneImgDetResult->CutRoi.y; + root["cutRoi"]["width"] = m_pOneImgDetResult->CutRoi.width; + root["cutRoi"]["height"] = m_pOneImgDetResult->CutRoi.height; + } + { + + root["Param_CropRoi"]["x"] = m_pOneImgDetResult->Param_CropRoi.x; + root["Param_CropRoi"]["y"] = m_pOneImgDetResult->Param_CropRoi.y; + root["Param_CropRoi"]["width"] = m_pOneImgDetResult->Param_CropRoi.width; + root["Param_CropRoi"]["height"] = m_pOneImgDetResult->Param_CropRoi.height; + } + for (int i = 0; i < m_pOneImgDetResult->pQx_ErrorList->size(); i++) + { + QX_ERROR_INFO_ *p = &m_pOneImgDetResult->pQx_ErrorList->at(i); + Json::Value value; + { + + value["Idx"] = p->Idx; + value["result"] = p->result; + value["result_Name"] = p->result_name; + value["roi"]["x"] = p->roi.x; + value["roi"]["y"] = p->roi.y; + value["roi"]["width"] = p->roi.width; + value["roi"]["height"] = p->roi.height; + value["area"] = p->area; + value["energy"] = p->energy; + value["JudgArea"] = p->JudgArea; + value["JudgArea_second"] = p->JudgArea_second; + value["flen"] = p->flen; + value["nconfig_qx_type"] = p->nconfig_qx_type; + value["qx_name"] = p->qx_name; + value["maxValue"] = p->maxValue; + value["grayDis"] = p->grayDis; + value["fUpIou"] = p->fUpIou; + value["density"] = p->density; + // return root; + for (int jr = 0; jr < p->detRegionidxList.size(); jr++) + { + + value["regionlist"].append(p->detRegionidxList[jr]); + } + } + root["Qx"].append(value); + } + + return root; +} + +void CheckResultJson::toObjectFromValue(Json::Value root) +{ + + m_pOneImgDetResult = std::make_shared(); + m_pOneImgDetResult->pQx_ErrorList = std::make_shared>(); + // std::cout << root << std::endl; + + { + auto value = root["cutRoi"]; + if (value.isObject()) + { + + m_pOneImgDetResult->CutRoi.x = root["cutRoi"]["x"].asInt(); + m_pOneImgDetResult->CutRoi.y = root["cutRoi"]["y"].asInt(); + m_pOneImgDetResult->CutRoi.width = root["cutRoi"]["width"].asInt(); + m_pOneImgDetResult->CutRoi.height = root["cutRoi"]["height"].asInt(); + } + } + { + auto value = root["Param_CropRoi"]; + if (value.isObject()) + { + + m_pOneImgDetResult->Param_CropRoi.x = root["Param_CropRoi"]["x"].asInt(); + m_pOneImgDetResult->Param_CropRoi.y = root["Param_CropRoi"]["y"].asInt(); + m_pOneImgDetResult->Param_CropRoi.width = root["Param_CropRoi"]["width"].asInt(); + m_pOneImgDetResult->Param_CropRoi.height = root["Param_CropRoi"]["height"].asInt(); + } + } + { + if (root.isMember("Qx")) + { + + const Json::Value &errorList = root["Qx"]; + for (const auto &errorJson : errorList) + { + + QX_ERROR_INFO_ tem; + tem.Idx = errorJson["Idx"].asInt(); + + // tem.result = errorJson["result"].asInt(); + // tem.result_name = errorJson["result_Name"].asString(); + + tem.roi.x = errorJson["roi"]["x"].asInt(); + tem.roi.y = errorJson["roi"]["y"].asInt(); + tem.roi.width = errorJson["roi"]["width"].asInt(); + tem.roi.height = errorJson["roi"]["height"].asInt(); + tem.area = errorJson["area"].asInt(); + tem.energy = errorJson["energy"].asInt(); + tem.JudgArea = errorJson["JudgArea"].asFloat(); + if (errorJson["JudgArea_second"]) + { + tem.JudgArea_second = errorJson["JudgArea_second"].asFloat(); + } + else + { + tem.JudgArea_second = tem.JudgArea; + } + + tem.flen = errorJson["flen"].asFloat(); + tem.nconfig_qx_type = errorJson["nconfig_qx_type"].asInt(); + tem.qx_name = errorJson["qx_name"].asString(); + tem.maxValue = errorJson["maxValue"].asInt(); + tem.grayDis = errorJson["grayDis"].asFloat(); + tem.fUpIou = errorJson["fUpIou"].asFloat(); + tem.density = errorJson["density"].asFloat(); + + const Json::Value ®ionvalue = errorJson["regionlist"]; + + if (regionvalue.isArray()) + { + // std::cout<pQx_ErrorList->push_back(tem); + + // tem.print(std::to_string(m_pOneImgDetResult->pQx_ErrorList->size())); + } + } + } +} + +int CheckResultJson::GetConfig(std::string strJson, std::shared_ptr &pOneImgDetResult) +{ + Json::CharReader *reader = readerBuilder.newCharReader(); + string errs; + bool parsingSuccessful = reader->parse(strJson.c_str(), strJson.c_str() + strJson.size(), &root, &errs); + delete reader; + if (!parsingSuccessful) + { + cout << "Failed to parse JSON string: " << errs << endl; + return 1; + } + toObjectFromValue(root); + pOneImgDetResult = m_pOneImgDetResult; + return 0; +} + +std::string CheckResultJson::GetResultString(std::shared_ptr &pOneImgDetResult) +{ + m_pOneImgDetResult = pOneImgDetResult; + + Json::Value root = toJsonValue(); + Json::StreamWriterBuilder writerBuilder; + std::string jsonString = Json::writeString(writerBuilder, root); + + return jsonString; +} diff --git a/AlgorithmModule/src/CheckUtil.cpp b/AlgorithmModule/src/CheckUtil.cpp new file mode 100644 index 0000000..ebf480a --- /dev/null +++ b/AlgorithmModule/src/CheckUtil.cpp @@ -0,0 +1,658 @@ +/* + * FileName:CoreLogicFactory.cpp + * Version:V1.0 + * Description: + * Created On:Mon Sep 10 11:13:16 UTC 2018 + * Modified date: + * Author:Sky + */ +#include "CheckUtil.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "snowflake.hpp" + +int _sysmkdir_2(const std::string &dir) +{ + int ret = mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if (ret && errno == EEXIST) + { + // printf("dir[%s] already exist.\n", dir.c_str()); + } + else if (ret) + { + printf("create dir[%s] error: %d %s\n", dir.c_str(), ret, strerror(errno)); + return -1; + } + else + { + printf("create dir[%s] success.\n", dir.c_str()); + } + return 0; +} +std::string __getParentDir_2(const std::string &dir) +{ + std::string pdir = dir; + if (pdir.length() < 1 || (pdir[0] != '/')) + { + return ""; + } + while (pdir.length() > 1 && (pdir[pdir.length() - 1] == '/')) + pdir = pdir.substr(0, pdir.length() - 1); + + pdir = pdir.substr(0, pdir.find_last_of('/')); + return pdir; +} + +long CheckUtil::getcurTime() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return ((long)tv.tv_sec) * 1000 + ((long)tv.tv_usec) / 1000; +} +std::string CheckUtil::getCurrentDate() +{ + struct timeval tv; + gettimeofday(&tv, NULL); // 获取当前时间 + + // 将 tv_sec 转换为 time_t 类型,代表自1970年1月1日起的秒数 + time_t raw_time = tv.tv_sec; + + // 使用 localtime 将 time_t 转换为 tm 结构体 + struct tm *time_info = localtime(&raw_time); + + // 使用字符串流格式化为 "YYYY-MM-DD" + std::ostringstream oss; + oss << (time_info->tm_year + 1900) << "-" // tm_year 是从1900年开始的 + << (time_info->tm_mon + 1) << "-" // tm_mon 是从0开始的 + << time_info->tm_mday; // tm_mday 是当前月的天数 + + return oss.str(); // 返回日期字符串 +} +std::string CheckUtil::getCurTimeHMS() +{ + struct timeval tv; + gettimeofday(&tv, NULL); // 获取当前时间 + + time_t raw_time = tv.tv_sec; + struct tm *time_info = localtime(&raw_time); + + int millisec = tv.tv_usec / 1000; // 微秒转毫秒 + + std::ostringstream oss; + oss << std::setfill('0') << std::setw(2) << time_info->tm_hour << ":" + << std::setfill('0') << std::setw(2) << time_info->tm_min << ":" + << std::setfill('0') << std::setw(2) << time_info->tm_sec << "." + << std::setfill('0') << std::setw(3) << millisec; + + return oss.str(); // 返回格式 "HH:MM:SS.mmm" +} +std::string CheckUtil::Op_float2String(float nvalue) +{ + char buffer[20]; + sprintf(buffer, "%.1f", nvalue); + std::string st1 = buffer; + return st1; +} + +int64_t CheckUtil::getSnowId() +{ + using snowflake_t = snowflake<1534832906275L, std::mutex>; + static snowflake_t uuid; + static bool bInit = false; + if (!bInit) + { + uuid.init(1, 1); + bInit = true; + } + return uuid.nextid(); + return 0; +} + +bool CheckUtil::JudgRect(cv::Rect roi, int img_w, int img_h) +{ + if (img_w <= 0 || img_h <= 0) + { + return false; + } + if (roi.x < 0 || roi.x >= img_w) + { + return false; + } + if (roi.width <= 0 || roi.width >= img_w) + { + return false; + } + if (roi.y < 0 || roi.y >= img_h) + { + return false; + } + if (roi.height <= 0 || roi.height >= img_h) + { + return false; + } + if (roi.x + roi.width >= img_w) + { + return false; + } + if (roi.y + roi.height >= img_h) + { + return false; + } + return true; +} + +bool CheckUtil::JudgRect_SZ(cv::Rect roi, int w, int h) +{ + if (roi.x < 0 || roi.x >= w) + { + return false; + } + if (roi.width <= 0 || roi.width != w) + { + return false; + } + if (roi.y < 0 || roi.y >= h) + { + return false; + } + if (roi.height <= 0 || roi.height != h) + { + return false; + } + + return true; +} +bool CheckUtil::compareIgnoreCase(const std::string &str1, const std::string &str2) +{ + // 将 str1 和 str2 转换为小写后进行比较 + std::string lower_str1 = str1; + std::string lower_str2 = str2; + + // 使用 std::transform 将字符串转换为小写 + std::transform(lower_str1.begin(), lower_str1.end(), lower_str1.begin(), ::tolower); + std::transform(lower_str2.begin(), lower_str2.end(), lower_str2.begin(), ::tolower); + + // 比较两个转换后的字符串 + return lower_str1 == lower_str2; +} + +bool CheckUtil::RoiInImg(cv::Rect roi, cv::Mat img) +{ + if (roi.width <= 0 || roi.height <= 0) + { + return false; + } + + if ((roi & cv::Rect(0, 0, img.cols, img.rows)) == roi) + { + return true; + } + + return false; +} + +int CheckUtil::printROI(cv::Rect roi, std::string str) +{ + printf("%s x %d y %d w %d h %d\n", str.c_str(), roi.x, roi.y, roi.width, roi.height); + return 0; +} + +float CheckUtil::CalIoU(cv::Rect rect1, cv::Rect rect2) +{ + // 计算交集区域 + cv::Rect intersection = rect1 & rect2; + + // 计算并集区域 + cv::Rect union_rect = rect1 | rect2; + + // 计算交集区域和并集区域的面积 + double intersection_area = intersection.area(); + double union_area = union_rect.area(); + + // 计算IoU值 + double iou = intersection_area / union_area; + + return iou; +} + +float CheckUtil::CalIoU_t(cv::Rect rect1, cv::Rect rect2) +{ + // 计算交集区域 + cv::Rect intersection = rect1 & rect2; + + // 计算并集区域 + cv::Rect union_rect = rect1; + + // 计算交集区域和并集区域的面积 + double intersection_area = intersection.area(); + double union_area = union_rect.area(); + + // 计算IoU值 + double iou = intersection_area / union_area; + + return iou; +} + +int CheckUtil::CheckRect(cv::Rect &roi, int img_w, int img_h) +{ + if (roi.x < 0 || roi.x >= img_w) + { + roi.x = 0; + } + if (roi.y < 0 || roi.y >= img_h) + { + roi.y = 0; + } + if (roi.width <= 0 || roi.width > img_w) + { + roi.width = 1; + } + if (roi.height <= 0 || roi.height > img_h) + { + roi.height = 1; + } + if (roi.x + roi.width > img_w) + { + roi.x = img_w - roi.width; + if (roi.x < 0) + { + roi.x = 0; + roi.width = img_w; + } + } + if (roi.y + roi.height > img_h) + { + roi.y = img_h - roi.height; + if (roi.y < 0) + { + roi.y = 0; + roi.height = img_h; + } + } + + return 0; +} + +int CheckUtil::SizeRect(cv::Rect &roi, int img_w, int img_h, int addw, int addh) +{ + if (roi.width + 2 * addw > img_w) + { + return 1; + } + if (roi.height + 2 * addh > img_h) + { + return 1; + } + int sx = roi.x - addw; + int ex = roi.x + roi.width + addw; + if (sx < 0) + { + sx = 0; + } + if (ex > img_w) + { + ex = img_w; + } + + int sy = roi.y - addh; + int ey = roi.y + roi.height + addh; + if (sy < 0) + { + sy = 0; + } + if (ey > img_h) + { + ey = img_h; + } + + roi.x = sx; + roi.width = ex - sx; + roi.y = sy; + roi.height = ey - sy; + return 0; +} + +int CheckUtil::CalHj(const cv::Mat &img, const cv::Mat &mask, int b_value) +{ + cv::Mat imgf; + if (img.type() != CV_32F) + img.convertTo(imgf, CV_32F); + else + imgf = img; + + // 2. 减去常数并取绝对值 + cv::Mat absDiff = cv::abs(imgf - b_value); + + // 3. 用 mask 计算平均值 + cv::Scalar meanValue123 = cv::mean(absDiff, mask); + + return meanValue123[0]; +} + +int CheckUtil::CalHj(const cv::Mat &img, const cv::Mat &mask, const cv::Mat &backgroundimg) +{ + cv::Mat imgf; + if (img.type() != CV_32F) + img.convertTo(imgf, CV_32F); + else + imgf = img; + + cv::Scalar meanValue = cv::mean(backgroundimg); + int b_value = meanValue[0]; + // 2. 减去常数并取绝对值 + cv::Mat absDiff = cv::abs(imgf - b_value); + + // 3. 用 mask 计算平均值 + cv::Scalar meanValue123 = cv::mean(absDiff, mask); + + return meanValue123[0]; +} + +int CheckUtil::CalHjWeighted(const cv::Mat &img, const cv::Mat &mask, int b_value, float power) +{ + cv::Mat imgf; + if (img.type() != CV_32F) + img.convertTo(imgf, CV_32F); + else + imgf = img; + + cv::Mat absDiff = cv::abs(imgf - b_value); + + cv::Mat weight; + cv::pow(absDiff, power, weight); + + cv::Mat maskedDiff, maskedWeight; + absDiff.copyTo(maskedDiff, mask); + weight.copyTo(maskedWeight, mask); + + cv::Scalar weightedSum = cv::sum(maskedDiff.mul(weight)); + cv::Scalar weightSum = cv::sum(maskedWeight); + + if (weightSum[0] < 1e-6) + return 0; + + return static_cast(weightedSum[0] / weightSum[0]); +} + +float CheckUtil::CalImgBrightness(cv::Mat imgRoi) +{ + if (imgRoi.empty()) + { + return 0.0f; + } + cv::Mat mat_mean, mat_stddev; + cv::meanStdDev(imgRoi, mat_mean, mat_stddev); // 求灰度图像的均值、均方差 + float m = mat_mean.at(0, 0); + return m; +} + +float CheckUtil::Cal2PointAngle(cv::Point p_left, cv::Point p_right) +{ + double angle = std::atan2(p_left.y - p_right.y, p_right.x - p_left.x); + return angle * 180 / 3.1415926; +} + +cv::Rect CheckUtil::getLargestContourROI(const cv::Mat &binaryImg, bool &found) +{ + std::vector> contours; + std::vector hierarchy; + + // 查找轮廓 + cv::findContours(binaryImg.clone(), contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); + + found = false; + if (contours.empty()) + { + return cv::Rect(); // 返回空Rect + } + + // 找到面积最大的轮廓 + double maxArea = 0; + int maxAreaIdx = -1; + for (size_t i = 0; i < contours.size(); i++) + { + double area = cv::contourArea(contours[i]); + if (area > maxArea) + { + maxArea = area; + maxAreaIdx = i; + } + } + + // 如果没有找到有效轮廓(比如所有轮廓面积都为0) + if (maxAreaIdx == -1 || maxArea <= 0) + { + return cv::Rect(); + } + + found = true; + // 返回最大轮廓的边界矩形 + return cv::boundingRect(contours[maxAreaIdx]); +} + +std::string CheckUtil::GetRectString(cv::Rect rect) +{ + std::string str = "[" + std::to_string(rect.x) + "," + std::to_string(rect.y) + "," + std::to_string(rect.width) + "," + std::to_string(rect.height) + "]"; + return str; +} + +int CheckUtil::CreateDir(const std::string &dir) +{ + int ret = 0; + if (dir.empty()) + return -1; + std::string pdir; + if ((ret = _sysmkdir_2(dir)) == -1) + { + pdir = __getParentDir_2(dir); + if ((ret = CreateDir(pdir)) == 0) + { + ret = CreateDir(dir); + } + } + + return ret; +} + +bool CheckUtil::bcalDis(cv::Point p1, cv::Point p2, int disT) +{ + double dis = std::sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); + if (dis < disT) + return true; + return false; +} + +double CheckUtil::calDis(cv::Point p1, cv::Point p2) +{ + double dis = std::sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); + return dis; +} + +void CheckUtil::PrintRect(cv::Rect roi, std::string str) +{ + printf("%s x %d y %d w %d h %d \n", str.c_str(), roi.x, roi.y, roi.width, roi.height); +} + +int CheckUtil::cutSmallImg(cv::Mat img, std::vector &samllRoiList, cv::Rect config_roi, int config_SmallImg_Width, int config_SmallImg_Height, int config_MinOverlap_Width, int config_MinOverlap_Height) +{ + if (img.empty()) + { + printf("error >>>> img.empty \n"); + return 1; + /* code */ + } + if (!RoiInImg(config_roi, img)) + { + printf("error >>>> roi != img size \n"); + return 2; + } + if (config_SmallImg_Width <= 0 || + config_SmallImg_Height <= 0 || + config_SmallImg_Width > img.cols || + config_SmallImg_Height > img.rows) + { + printf("error >>>>config_SmallImg_Width %d config_SmallImg_Height %d \n ", config_SmallImg_Width, config_SmallImg_Height); + return 3; + } + if (config_MinOverlap_Width < 0 || + config_MinOverlap_Height < 0 || + config_MinOverlap_Width > img.cols || + config_MinOverlap_Height > img.rows || + config_MinOverlap_Width >= config_SmallImg_Width || + config_MinOverlap_Height >= config_SmallImg_Height) + { + printf("error >>>>config_MinOverlap_Width %d config_MinOverlap_Height %d \n ", config_MinOverlap_Width, config_MinOverlap_Height); + return 4; + } + + int AI_Img_width = config_SmallImg_Width; + int AI_Img_height = config_SmallImg_Height; + + int start_x = config_roi.x; + int start_y = config_roi.y; + + int end_x = config_roi.width + config_roi.x; + int end_y = config_roi.height + config_roi.y; + + // 有效图片 宽 高 + int det_width = config_roi.width; + int det_height = config_roi.height; + + if (AI_Img_width > det_width || AI_Img_height > det_height) + { + printf("error >>>>config_SmallImg_Width %d != roi width %d \n ", config_SmallImg_Width, det_width); + printf("error >>>>config_SmallImg_Height %d != roi height %d \n ", config_SmallImg_Height, det_height); + return 5; + } + + // printf("config_SmallImg_Width %d config_SmallImg_Height %d \n ", config_SmallImg_Width, config_SmallImg_Height); + // printf("config_MinOverlap_Width %d config_MinOverlap_Height %d \n ", config_MinOverlap_Width, config_MinOverlap_Height); + + /////////////////、计算宽度方向 块的个数 和 重叠 /////////////////////// + // 可分为多少块 宽度度方向 + float fBlocknum_x = det_width * 1.0f / AI_Img_width; + // 块的个数 + int nBlocknum_x = std::ceil(fBlocknum_x); + + // 如果 有重叠要求 + if (config_MinOverlap_Width >= 0) + { + float fconfig_BlocknuNum_x = (det_width - AI_Img_width) * 1.0f / (config_SmallImg_Width - config_MinOverlap_Width) + 1; + int nconfig_BlocknuNum_x = std::ceil(fconfig_BlocknuNum_x); + if (nBlocknum_x < nconfig_BlocknuNum_x) + { + nBlocknum_x = nconfig_BlocknuNum_x; + } + } + int use_MinOverlap_Width = 0; + // 计算重叠率 + if (nBlocknum_x > 1) + { + // 有多个块,要判断 块的重叠是否满足要求 + int nSumLen_x = nBlocknum_x * AI_Img_width; // + float fOverlap_x = (nSumLen_x - det_width) * 1.0f / (nBlocknum_x - 1); + use_MinOverlap_Width = int(fOverlap_x); + } + // printf("nBlocknum_x %d use_MinOverlap_Width %d \n", nBlocknum_x, use_MinOverlap_Width); + + /////////////////、计算高度方向 块的个数 和 重叠 /////////////////////// + // 可分为多少块 高度方向 + float fBlocknum_y = det_height * 1.0f / AI_Img_height; + // 块的个数 + int nBlocknum_y = std::ceil(fBlocknum_y); + + // 如果 有重叠要求 + if (config_MinOverlap_Height >= 0) + { + float fconfig_BlocknuNum_y = (det_height - AI_Img_height) * 1.0f / (config_SmallImg_Height - config_MinOverlap_Height) + 1; + int nconfig_BlocknuNum_y = std::ceil(fconfig_BlocknuNum_y); + if (nBlocknum_y < nconfig_BlocknuNum_y) + { + nBlocknum_y = nconfig_BlocknuNum_y; + } + } + int use_MinOverlap_Height = 0; + // 计算重叠率 + if (nBlocknum_y > 1) + { + // 有多个块,要判断 块的重叠是否满足要求 + int nSumLen_y = nBlocknum_y * AI_Img_height; // + float fOverlap_y = (nSumLen_y - det_height) * 1.0f / (nBlocknum_y - 1); + use_MinOverlap_Height = int(fOverlap_y); + } + + // printf("nBlocknum_y %d use_MinOverlap_Height %d \n", nBlocknum_y, use_MinOverlap_Height); + + int cut_sy = start_y; + int cut_ey = start_y + AI_Img_height; + + for (int iy = 0; iy < nBlocknum_y; iy++) + { + int nleny = end_y - cut_ey; + + int cut_sx = start_x; + int cut_ex = start_x + AI_Img_width; + for (int ix = 0; ix < nBlocknum_x; ix++) + { + + cv::Rect roi; + roi.x = cut_sx; + roi.y = cut_sy; + roi.width = AI_Img_width; + roi.height = AI_Img_height; + + samllRoiList.push_back(roi); + + // 剩余长度 + int nlenx = end_x - cut_ex; + if (nlenx > AI_Img_width) + { + cut_sx = cut_sx + AI_Img_width - use_MinOverlap_Width; + cut_ex = cut_sx + AI_Img_width; + } + else + { + cut_sx = end_x - AI_Img_width; + cut_ex = cut_sx + AI_Img_width; + } + } + + if (nleny > AI_Img_height) + { + cut_sy = cut_sy + AI_Img_height - use_MinOverlap_Height; + cut_ey = cut_sy + AI_Img_height; + } + else + { + cut_sy = end_y - AI_Img_height; + cut_ey = cut_sy + AI_Img_height; + } + } + + return 0; +} +cv::Point2f CheckUtil::transformPoint(const cv::Point2f &point, const cv::Mat &transform_matrix) +{ + // 验证变换矩阵有效性 + if (transform_matrix.empty() || transform_matrix.rows != 2 || transform_matrix.cols != 3) + { + std::cerr << "Error: Invalid transformation matrix! Returning original point." << std::endl; + return point; + } + + // 使用矩阵乘法进行点变换 + cv::Mat point_mat = (cv::Mat_(3, 1) << point.x, point.y, 1); + cv::Mat result_mat = transform_matrix * point_mat; + + return cv::Point2f(result_mat.at(0), result_mat.at(1)); +} \ No newline at end of file diff --git a/AlgorithmModule/src/Edge_QX_Det.cpp b/AlgorithmModule/src/Edge_QX_Det.cpp new file mode 100644 index 0000000..ca1f0a2 --- /dev/null +++ b/AlgorithmModule/src/Edge_QX_Det.cpp @@ -0,0 +1,1671 @@ + +#include "Edge_QX_Det.h" +#include +#include +// 计算平均值 +double computeAverage123(const std::vector &data) +{ + return std::accumulate(data.begin(), data.end(), 0.0) / data.size(); +} + +// 剔除异常数据,这里以平均值加减两倍标准差为界限 +std::vector removeOutliers123(const std::vector &data) +{ + double mean = computeAverage123(data); + double sq_sum = std::inner_product(data.begin(), data.end(), data.begin(), 0.0); + double stdev = std::sqrt(sq_sum / data.size() - mean * mean); + std::vector filteredData; + for (double value : data) + { + if (std::abs(value - mean) <= 2 * stdev) + { // 可以根据需要调整异常值判断的标准 + filteredData.push_back(value); + } + } + return filteredData; +} +// 计算点到直线距离 +float pointToLineDistance(const cv::Point &pt, const cv::Vec4f &line) +{ + float vx = line[0], vy = line[1], x0 = line[2], y0 = line[3]; + float x = pt.x, y = pt.y; + return std::abs(vy * x - vx * y + (vx * y0 - vy * x0)) / std::sqrt(vx * vx + vy * vy); +} +bool FitLineWithOutlierRemoval(const std::vector &inputPoints, cv::Vec4f &outputLine, int ransacIters = 100, float inlierThresh = 10) +{ + if (inputPoints.size() < 2) + return false; + + int bestInliers = 0; + std::vector bestInlierPoints; + + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> dis(0, inputPoints.size() - 1); + + for (int i = 0; i < ransacIters; ++i) + { + int idx1 = dis(gen); + int idx2 = dis(gen); + if (idx1 == idx2) + continue; + + cv::Point p1 = inputPoints[idx1]; + cv::Point p2 = inputPoints[idx2]; + if (p1 == p2) + continue; + + cv::Vec4f tempLine; + tempLine[0] = p2.x - p1.x; + tempLine[1] = p2.y - p1.y; + tempLine[2] = p1.x; + tempLine[3] = p1.y; + + std::vector inliers; + for (const auto &pt : inputPoints) + { + float dist = std::abs(tempLine[1] * pt.x - tempLine[0] * pt.y + tempLine[0] * tempLine[3] - tempLine[1] * tempLine[2]) / + std::sqrt(tempLine[0] * tempLine[0] + tempLine[1] * tempLine[1]); + if (dist < inlierThresh) + inliers.push_back(pt); + } + + if (inliers.size() > bestInliers) + { + bestInliers = inliers.size(); + bestInlierPoints = inliers; + } + } + + if (bestInlierPoints.size() < 2) + return false; + + cv::fitLine(bestInlierPoints, outputLine, cv::DIST_L2, 0, 0.01, 0.01); + return true; +} + +void drawFittedLine(cv::Mat &image, const cv::Vec4f &line, const cv::Scalar &color, int thickness = 2) +{ + double scale = std::max(image.cols, image.rows) * 2.0; + cv::Point2f pt0(line[2], line[3]); // 起点 + cv::Point2f dir(line[0], line[1]); // 方向向量 + cv::Point2f pt1 = pt0 + scale * dir; // 向正方向延伸 + cv::Point2f pt2 = pt0 - scale * dir; // 向反方向延伸 + cv::line(image, pt1, pt2, color, thickness); // 绘制直线 +} + +// 计算两条直线的交点,返回是否成功 +bool GetLineIntersection(const cv::Vec4f &line1, const cv::Vec4f &line2, cv::Point2f &intersection) +{ + float vx1 = line1[0], vy1 = line1[1], x1 = line1[2], y1 = line1[3]; + float vx2 = line2[0], vy2 = line2[1], x2 = line2[2], y2 = line2[3]; + + // 解: (x1 + t1 * vx1, y1 + t1 * vy1) == (x2 + t2 * vx2, y2 + t2 * vy2) + // 即:解 t1 和 t2 联立方程 + + float det = vx1 * vy2 - vy1 * vx2; + + if (std::abs(det) < 1e-6) + { + // 平行或重合 + return false; + } + + float dx = x2 - x1; + float dy = y2 - y1; + float t = (dx * vy2 - dy * vx2) / det; + + intersection.x = x1 + t * vx1; + intersection.y = y1 + t * vy1; + return true; +} +bool Edge_QX_Det::GetSegmentIntersection(const Line &l1, const Line &l2, cv::Point2f &intersection) +{ + cv::Point2f p = l1.p1; + cv::Point2f r = l1.p2 - l1.p1; + cv::Point2f q = l2.p1; + cv::Point2f s = l2.p2 - l2.p1; + + float rxs = r.x * s.y - r.y * s.x; + + if (std::abs(rxs) < 1e-6) + return false; // 平行或重合 + + float t = ((q - p).x * s.y - (q - p).y * s.x) / rxs; + float u = ((q - p).x * r.y - (q - p).y * r.x) / rxs; + + if (t >= 0 && t <= 1 && u >= 0 && u <= 1) + { + intersection = p + t * r; + return true; + } + + return false; +} + +Edge_QX_Det::Edge_QX_Det() +{ + bshowimg = false; +} +Edge_QX_Det::~Edge_QX_Det() +{ +} +int Edge_QX_Det::Detect(const cv::Mat &img, DetConfigResult *pDetConfig) +{ + if (!pDetConfig->pBaseCheckFunction->edgeDet.bOpen) + { + return 0; + } + if (pDetConfig->pBaseCheckFunction->edgeDet.bDrawRoi) + { + return Draw_Det(img, pDetConfig); + } + + // if (pDetConfig->strChannel == "TA") + // { + // return 0; + // } + bshowimg = false; + if (pDetConfig->bSaveResultImg) + { + bshowimg = true; + } + bool bdetSucc = false; + + if (bshowimg) + { + cv::cvtColor(img, showimg, cv::COLOR_GRAY2BGR); + } + cv::Rect roi; + // printf("Edge_QX_Det::Detect\n"); + + // getchar(); + std::vector up_edge; + std::vector Up_line; + Edge_Search_Config config; + config.nSearchCount = 300; + config.strchannel = pDetConfig->strChannel; + config.directSign = DirectSign_UP; + config.roi = cv::Rect(0, 0, img.cols, 600); + int re123 = GetEdgePoint(img, &config, up_edge); + if (re123 != 0) + { + return 1; + } + + { + re123 = GetLine(img, up_edge, 30, 0, Up_line); + if (re123 != 0) + { + return 1; + } + } + // printf("DirectSign_UP::111111111111111111 re123 %d\n", re123); + + std::vector down_edge; + std::vector down_line; + config.directSign = DirectSign_DOWN; + config.roi = cv::Rect(0, img.rows - 600, img.cols, 600); + re123 = GetEdgePoint(img, &config, down_edge); + + if (re123 != 0) + { + return 1; + } + { + re123 = GetLine(img, down_edge, 30, 0, down_line); + if (re123 != 0) + { + return 1; + } + } + // printf("DirectSign_DOWN::111111111111111111 re123 %d\n", re123); + + std::vector left_edge; + std::vector left_line; + config.directSign = DirectSign_Left; + config.roi = cv::Rect(0, 0, 600, img.rows); + re123 = GetEdgePoint(img, &config, left_edge); + + if (re123 != 0) + { + return 1; + } + { + re123 = GetLine(img, left_edge, 15, 1, left_line); + if (re123 != 0) + { + return 1; + } + } + // printf("DirectSign_Left::111111111111111111 re123 %d\n", re123); + + std::vector right_edge; + std::vector right_line; + config.directSign = DirectSign_Right; + config.roi = cv::Rect(img.cols - 600, 0, 600, img.rows); + re123 = GetEdgePoint(img, &config, right_edge); + + if (re123 != 0) + { + return 1; + } + { + re123 = GetLine(img, right_edge, 15, 1, right_line); + if (re123 != 0) + { + return 1; + } + } + // printf("DirectSign_Right::111111111111111111 re123 %d\n", re123); + + // 求交点 + std::vector cornerPoints; + cv::Point2f pt; + + // 左上角:Up_line[0] 与 Left_line[0] + if (GetSegmentIntersection(Up_line[0], left_line[0], pt)) + { + pt.x += 10; + pt.y += 10; + cornerPoints.push_back(pt); + Up_line[0].p1 = pt; + left_line[0].p1 = pt; + } + + else + return 1; + + // 右上角:Up_line.back() 与 Right_line[0] + if (GetSegmentIntersection(Up_line.back(), right_line[0], pt)) + { + pt.x -= 10; + pt.y += 10; + cornerPoints.push_back(pt); + Up_line.back().p2 = pt; + right_line[0].p1 = pt; + } + else + return 1; + + // 右下角:Down_line.back() 与 Right_line.back() + if (GetSegmentIntersection(down_line.back(), right_line.back(), pt)) + { + pt.x -= 10; + pt.y -= 10; + cornerPoints.push_back(pt); + down_line.back().p2 = pt; + right_line.back().p2 = pt; + } + else + return 1; + + // 左下角:Down_line[0] 与 Left_line.back() + if (GetSegmentIntersection(down_line[0], left_line.back(), pt)) + { + pt.x += 10; + pt.y -= 10; + cornerPoints.push_back(pt); + down_line[0].p1 = pt; + left_line.back().p2 = pt; + } + else + return 1; + + // 生成 检测的 roi。 + int roi_wh = pDetConfig->pBaseCheckFunction->edgeDet.Det_Range; + + std::vector up_det_roi; + std::vector down_det_roi; + std::vector left_det_roi; + std::vector right_det_roi; + for (const auto &line : Up_line) + { + Det_ROI_Config tem; + tem.plist.push_back(line.p1); + tem.plist.push_back(line.p2); + + tem.plist.push_back(cv::Point(line.p2.x, line.p2.y + roi_wh)); + tem.plist.push_back(cv::Point(line.p1.x, line.p1.y + roi_wh)); + tem.roi = cv::boundingRect(tem.plist); + pDetConfig->edge_det_roi.push_back(tem); + up_det_roi.push_back(tem); + } + for (const auto &line : down_line) + { + Det_ROI_Config tem; + tem.plist.push_back(line.p1); + tem.plist.push_back(line.p2); + tem.plist.push_back(cv::Point(line.p2.x, line.p2.y - roi_wh)); + tem.plist.push_back(cv::Point(line.p1.x, line.p1.y - roi_wh)); + + tem.roi = cv::boundingRect(tem.plist); + pDetConfig->edge_det_roi.push_back(tem); + down_det_roi.push_back(tem); + } + for (const auto &line : left_line) + { + Det_ROI_Config tem; + tem.plist.push_back(line.p1); + tem.plist.push_back(line.p2); + tem.plist.push_back(cv::Point(line.p2.x + roi_wh, line.p2.y)); + tem.plist.push_back(cv::Point(line.p1.x + roi_wh, line.p1.y)); + + tem.roi = cv::boundingRect(tem.plist); + pDetConfig->edge_det_roi.push_back(tem); + left_det_roi.push_back(tem); + } + for (const auto &line : right_line) + { + Det_ROI_Config tem; + tem.plist.push_back(line.p1); + tem.plist.push_back(line.p2); + tem.plist.push_back(cv::Point(line.p2.x - roi_wh, line.p2.y)); + tem.plist.push_back(cv::Point(line.p1.x - roi_wh, line.p1.y)); + + tem.roi = cv::boundingRect(tem.plist); + pDetConfig->edge_det_roi.push_back(tem); + right_det_roi.push_back(tem); + } + // 检测缺陷 + Det_qx(img, up_det_roi, Det_ROI_Type_UP, pDetConfig); + Det_qx(img, down_det_roi, Det_ROI_Type_DOWN, pDetConfig); + Det_qx(img, left_det_roi, Det_ROI_Type_LEFT, pDetConfig); + Det_qx(img, right_det_roi, Det_ROI_Type_RIGHT, pDetConfig); + + if (bshowimg) + { + for (const auto &pt : cornerPoints) + { + cv::circle(showimg, pt, 5, cv::Scalar(0, 255, 255), -1); // 黄色角点 + } + + for (const auto &line : Up_line) + { + cv::line(showimg, line.p1, line.p2, cv::Scalar(255, 0, 0)); + cv::circle(showimg, line.p1, 4, cv::Scalar(0, 255, 255)); + cv::circle(showimg, line.p2, 4, cv::Scalar(0, 255, 255)); + } + for (const auto &line : down_line) + { + cv::line(showimg, line.p1, line.p2, cv::Scalar(255, 0, 0)); + cv::circle(showimg, line.p1, 4, cv::Scalar(0, 255, 255)); + cv::circle(showimg, line.p2, 4, cv::Scalar(0, 255, 255)); + } + for (const auto &line : left_line) + { + cv::line(showimg, line.p1, line.p2, cv::Scalar(255, 0, 0)); + cv::circle(showimg, line.p1, 4, cv::Scalar(0, 255, 255)); + cv::circle(showimg, line.p2, 4, cv::Scalar(0, 255, 255)); + } + for (const auto &line : right_line) + { + cv::line(showimg, line.p1, line.p2, cv::Scalar(255, 0, 0)); + cv::circle(showimg, line.p1, 4, cv::Scalar(0, 255, 255)); + cv::circle(showimg, line.p2, 4, cv::Scalar(0, 255, 255)); + } + for (auto p : up_edge) + { + cv::circle(showimg, p, 2, cv::Scalar(0, 255, 0)); + } + for (auto p : down_edge) + { + cv::circle(showimg, p, 2, cv::Scalar(0, 255, 0)); + } + for (auto p : left_edge) + { + cv::circle(showimg, p, 2, cv::Scalar(0, 255, 0)); + } + for (auto p : right_edge) + { + cv::circle(showimg, p, 2, cv::Scalar(0, 255, 0)); + } + for (const auto &r : pDetConfig->edge_det_roi) + { + cv::rectangle(showimg, r.roi, cv::Scalar(255, 0, 255), 3); // 黄色角点 + } + for (const auto r : pDetConfig->qx_result) + { + cv::rectangle(showimg, r.roi_src, cv::Scalar(255, 22, 100), 3); // 黄色角点 + } + + cv::imwrite(pDetConfig->strChannel + "_edge_show.png", showimg); + } + // printf("=================end==================\n"); + // getchar(); + + return 0; +} + +int Edge_QX_Det::GetEdgePoint(const cv::Mat &img, Edge_Search_Config *pEdge_Search_Config, std::vector &pointList) +{ + + bool bdbuge = false; + // bdbuge = bshowimg; + if (img.empty()) + { + return -11; + } + if (img.channels() != 1) + { + printf("*****************************channels\n"); + + return -12; + } + // 检查roi; + if (!CheckUtil::RoiInImg(pEdge_Search_Config->roi, img)) + { + return -13; + } + if (!pEdge_Search_Config->CheckConfigValid()) + { + return -14; + } + + bool search_UP_DOWN = false; + cv::Rect roi = pEdge_Search_Config->roi; + int sx = roi.x; + int ex = roi.x + roi.width; + int sy = roi.y; + int ey = roi.y + roi.height; + + int nSearchLen = roi.width; // 搜索区域的长度 + int nCurPoint_Step = pEdge_Search_Config->stepCount; // 当前点搜索的步长 + + // 搜索小范围确认 + int nhalfrang = (int)pEdge_Search_Config->nSearchrange / 2; + int nrange_start = 0 - nhalfrang; + int nrange_end = 0 - nhalfrang; + int num = 0; + while (true) + { + num++; + nrange_end++; + if (num >= pEdge_Search_Config->nSearchrange) + { + break; + } + } + // 判断方向 + switch (pEdge_Search_Config->directSign) + { + case DirectSign_UP: + search_UP_DOWN = true; + nSearchLen = roi.width; + sx = roi.x; + ex = roi.x + roi.width; + sy = roi.y; + ey = roi.y + roi.height; + nCurPoint_Step = pEdge_Search_Config->stepCount; + break; + case DirectSign_DOWN: + search_UP_DOWN = true; + nSearchLen = roi.width; + nCurPoint_Step = -pEdge_Search_Config->stepCount; + + sx = roi.x; + ex = roi.x + roi.width; + sy = roi.y + roi.height - 1; + ey = roi.y; + break; + case DirectSign_Left: + nSearchLen = roi.height; + search_UP_DOWN = false; + nCurPoint_Step = pEdge_Search_Config->stepCount; + + sx = roi.x; + ex = roi.x + roi.width; + sy = roi.y; + ey = roi.y + roi.height; + break; + case DirectSign_Right: + nSearchLen = roi.height; + search_UP_DOWN = false; + nCurPoint_Step = -pEdge_Search_Config->stepCount; + + sx = roi.x + roi.width - 1; + ex = roi.x; + sy = roi.y; + ey = roi.y + roi.height; + break; + default: + break; + } + + // 搜索 点数 + int nSearchPointNum = pEdge_Search_Config->nSearchCount; + // 搜素点的间隔 + int nSearchPointStep = 1; + if (nSearchPointNum > 1) + { + nSearchPointStep = int(nSearchLen * 1.0f / (nSearchPointNum - 1)); + } + + if (bdbuge) + { + cv::rectangle(showimg, roi, cv::Scalar(255, 0, 0), 2); + printf("nSearchPointStep %d nCurPoint_Step %d,nrange_start %d %d\n", nSearchPointStep, nCurPoint_Step, nrange_start, nrange_end); + } + + uchar *pdata = (uchar *)img.data; + int offt = 0; + // 搜索 上下边 + if (search_UP_DOWN) + { + // 每个搜索点 分布在X方向。 + for (int x = sx; x < ex; x = x + nSearchPointStep) + { + int bOKNum = 0; + int cur_x = x; + int cur_y = sy; + bool bSucc = false; + + // 对每个搜索点进行 y方向搜索 + for (int y = sy;; y = y + nCurPoint_Step) + { + if (y < 0 || y >= img.rows) + { + continue; + } + + // + if (nCurPoint_Step > 0 && y > ey) + { + break; + } + if (nCurPoint_Step < 0 && y < ey) + { + break; + } + offt = y * img.cols; + int range_okNum = 0; + // 对一定范围的点进行判断 + for (int k = nrange_start; k < nrange_end; k++) + { + int rangeX = x + k; + if (rangeX < 0 || rangeX >= img.cols) + { + continue; + } + offt += rangeX; + if (offt < 0 || offt >= img.cols * img.rows) + { + printf("rangeX %d nCurPoint_Step %d off %d x %d y %d sy %d ey %d %d %d\n", rangeX, nCurPoint_Step, offt, x, y, sy, ey, img.cols, img.rows); + } + + if (pdata[offt] >= pEdge_Search_Config->nValueThreshold) // 找到 + { + range_okNum++; + } + } + if (range_okNum >= pEdge_Search_Config->nSearchrange) + { + if (bdbuge) + { + cv::circle(showimg, cv::Point(x, y), 1, cv::Scalar(0, 0, 255)); + } + if (bOKNum == 0) + { + cur_y = y; + } + + bOKNum++; + // 连续搜索到 满足要求的点。 + if (bOKNum >= pEdge_Search_Config->nLimit) + { + bSucc = true; + break; + } + } + else + { + // 如果有间断,需要重新计算连续情况。 + bOKNum = 0; + if (bdbuge) + { + cv::circle(showimg, cv::Point(x, y), 1, cv::Scalar(0, 255, 0)); + } + } + } + if (bSucc) + { + cv::Point p(cur_x, cur_y); + if (bdbuge) + { + cv::circle(showimg, p, 3, cv::Scalar(255, 0, 0)); + } + pointList.push_back(p); + } + } + } + else // 搜索 左右边 + { + // 每个搜索点 分布在X方向。 + for (int y = sy; y < ey; y = y + nSearchPointStep) + { + int bOKNum = 0; + int cur_x = sx; + int cur_y = y; + bool bSucc = false; + + // 对每个搜索点进行 y方向搜索 + for (int x = sx;; x = x + nCurPoint_Step) + { + if (x < 0 || x >= img.cols) + { + continue; + } + // + if (nCurPoint_Step > 0 && x > ex) + { + break; + } + if (nCurPoint_Step < 0 && x < ex) + { + break; + } + + int range_okNum = 0; + // 对一定范围的点进行判断 + for (int k = nrange_start; k < nrange_end; k++) + { + int rangey = y + k; + if (rangey < 0 || rangey >= img.rows) + { + continue; + } + offt = rangey * img.cols + x; + if (offt < 0 || offt >= img.cols * img.rows) + { + printf("rangey %d off %d x %d y %d ey %d %d %d\n", rangey, offt, x, y, ey, img.cols, img.rows); + } + if (pdata[offt] >= pEdge_Search_Config->nValueThreshold) // 找到 + { + range_okNum++; + } + } + if (range_okNum >= pEdge_Search_Config->nSearchrange) + { + if (bdbuge) + { + cv::circle(showimg, cv::Point(x, y), 1, cv::Scalar(0, 0, 255)); + } + if (bOKNum == 0) + { + cur_x = x; + } + + bOKNum++; + // 连续搜索到 满足要求的点。 + if (bOKNum >= pEdge_Search_Config->nLimit) + { + bSucc = true; + break; + } + } + else + { + // 如果有间断,需要重新计算连续情况。 + bOKNum = 0; + if (bdbuge) + { + cv::circle(showimg, cv::Point(x, y), 1, cv::Scalar(0, 255, 0)); + } + } + } + if (bSucc) + { + cv::Point p(cur_x, cur_y); + if (bdbuge) + { + cv::circle(showimg, p, 3, cv::Scalar(255, 0, 0)); + } + pointList.push_back(p); + } + } + } + + if (bdbuge) + { + cv::imwrite(pEdge_Search_Config->strchannel + "show.png", showimg); + } + + // getchar(); + + return 0; +} + +int Edge_QX_Det::GetLine(const cv::Mat &img, std::vector &pointList, int lineNum, int xory, std::vector &lineList) +{ + + lineList.clear(); + + if (pointList.size() < lineNum || lineNum <= 0) + return -1; + + const int maxDeviation = 10; // 可调阈值:最大允许偏离像素 + + std::vector avgPoints; + + size_t i = 0; + for (; i + lineNum <= pointList.size(); i += lineNum) + { + std::vector group(pointList.begin() + i, pointList.begin() + i + lineNum); + + // 第一次计算粗略均值 + int sum_y = 0, sum_x = 0; + for (const auto &pt : group) + { + sum_x += pt.x; + sum_y += pt.y; + } + float avg_y = sum_y * 1.0f / lineNum; + float avg_x = sum_x * 1.0f / lineNum; + + // 过滤异常点 + std::vector filtered; + for (const auto &pt : group) + { + if (xory == 0) // 横向:判断 y 偏差 + { + if (std::abs(pt.y - avg_y) <= maxDeviation) + filtered.push_back(pt); + } + else // 纵向:判断 x 偏差 + { + if (std::abs(pt.x - avg_x) <= maxDeviation) + filtered.push_back(pt); + } + } + + if (filtered.empty()) + continue; // 本组全是异常点,跳过 + + // 用过滤后的点重新计算平均 + int sum_fx = 0, sum_fy = 0; + for (const auto &pt : filtered) + { + sum_fx += pt.x; + sum_fy += pt.y; + } + avgPoints.emplace_back(sum_fx / (int)filtered.size(), sum_fy / (int)filtered.size()); + } + + // 末尾不足 lineNum,用最后 lineNum 个点 + if (pointList.size() % lineNum != 0 && pointList.size() >= lineNum) + { + size_t start = pointList.size() - lineNum; + std::vector group(pointList.begin() + start, pointList.end()); + + int sum_x = 0, sum_y = 0; + for (const auto &pt : group) + { + sum_x += pt.x; + sum_y += pt.y; + } + float avg_y = sum_y * 1.0f / lineNum; + float avg_x = sum_x * 1.0f / lineNum; + + // 过滤异常点 + std::vector filtered; + for (const auto &pt : group) + { + if (xory == 0) + { + if (std::abs(pt.y - avg_y) <= maxDeviation) + filtered.push_back(pt); + } + else + { + if (std::abs(pt.x - avg_x) <= maxDeviation) + filtered.push_back(pt); + } + } + + if (!filtered.empty()) + { + int sum_fx = 0, sum_fy = 0; + for (const auto &pt : filtered) + { + sum_fx += pt.x; + sum_fy += pt.y; + } + avgPoints.emplace_back(sum_fx / (int)filtered.size(), sum_fy / (int)filtered.size()); + } + } + + if (avgPoints.empty()) + return -2; + + // 构建线段(起点终点规则) + if (xory == 0) + { + Line first; + first.p1 = cv::Point(0, avgPoints[0].y); + first.p2 = avgPoints[0]; + lineList.push_back(first); + + for (size_t k = 0; k + 1 < avgPoints.size(); ++k) + { + Line mid; + mid.p1 = avgPoints[k]; + mid.p2 = avgPoints[k + 1]; + lineList.push_back(mid); + } + + Line last; + last.p1 = avgPoints.back(); + last.p2 = cv::Point(img.cols, avgPoints.back().y); + lineList.push_back(last); + } + else + { + Line first; + first.p1 = cv::Point(avgPoints[0].x, 0); + first.p2 = avgPoints[0]; + lineList.push_back(first); + + for (size_t k = 0; k + 1 < avgPoints.size(); ++k) + { + Line mid; + mid.p1 = avgPoints[k]; + mid.p2 = avgPoints[k + 1]; + lineList.push_back(mid); + } + + Line last; + last.p1 = avgPoints.back(); + last.p2 = cv::Point(avgPoints.back().x, img.rows); + lineList.push_back(last); + } + + return 0; +} + +int Edge_QX_Det::Det_qx(const cv::Mat &img, std::vector roilist, Det_ROI_Type type, DetConfigResult *pDetConfig) +{ + if (img.empty()) + { + return -11; + } + if (img.channels() != 1) + { + printf("*****************************channels\n"); + return -12; + } + Base_Function_Edge_Det *pedgeDet = &pDetConfig->pBaseCheckFunction->edgeDet; + vector allPoints; + + for (const auto &ROI : roilist) + { + allPoints.insert(allPoints.end(), ROI.plist.begin(), ROI.plist.end()); + } + if (allPoints.size() <= 0) + { + return 1; + } + cv::Rect DetRoi = cv::boundingRect(allPoints); + cv::Mat roiMask = cv::Mat::zeros(DetRoi.height, DetRoi.width, CV_8UC1); + + for (const auto &ROI : roilist) + { + cv::Mat mask; + applyMaskInROI(img, ROI, mask, pedgeDet->Det_threshold); + cv::Rect detimg_roi; + detimg_roi.x = ROI.roi.x - DetRoi.x; + detimg_roi.y = ROI.roi.y - DetRoi.y; + detimg_roi.width = ROI.roi.width; + detimg_roi.height = ROI.roi.height; + mask.copyTo(roiMask(detimg_roi), mask); + } + int erx = pedgeDet->QX_Widht_min; + int ery = pedgeDet->QX_Height_min; + if (erx < 3) + { + erx = 3; + } + if (ery < 3) + { + ery = 3; + } + + cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(erx, ery)); + + // 进行开操作(先腐蚀后膨胀)可以去除小白点 + cv::morphologyEx(roiMask, roiMask, cv::MORPH_OPEN, kernel); + // cv::imwrite("detimg.png", img(DetRoi)); + // cv::imwrite("detimg_mask.png", roiMask); + // getchar(); + + bool jiao_f_1 = false; + bool jiao_f_2 = false; + cv::Point jiao_p_1; + cv::Point jiao_p_2; + if (type == Det_ROI_Type_UP) + { + jiao_f_1 = pDetConfig->pBaseCheckFunction->edgeDet.queJiao_LU_Open; + jiao_f_2 = pDetConfig->pBaseCheckFunction->edgeDet.queJiao_RU_Open; + jiao_p_1 = cv::Point(0, 0); + jiao_p_2 = cv::Point(roiMask.cols, 0); + } + else if (type == Det_ROI_Type_DOWN) + { + jiao_f_1 = pDetConfig->pBaseCheckFunction->edgeDet.queJiao_LD_Open; + jiao_f_2 = pDetConfig->pBaseCheckFunction->edgeDet.queJiao_RD_Open; + jiao_p_1 = cv::Point(0, roiMask.rows); + jiao_p_2 = cv::Point(roiMask.cols, roiMask.rows); + } + else if (type == Det_ROI_Type_LEFT) + { + jiao_f_1 = pDetConfig->pBaseCheckFunction->edgeDet.queJiao_LU_Open; + jiao_f_2 = pDetConfig->pBaseCheckFunction->edgeDet.queJiao_LD_Open; + + jiao_p_1 = cv::Point(0, 0); + jiao_p_2 = cv::Point(0, roiMask.rows); + } + else if (type == Det_ROI_Type_RIGHT) + { + jiao_f_1 = pDetConfig->pBaseCheckFunction->edgeDet.queJiao_RU_Open; + jiao_f_2 = pDetConfig->pBaseCheckFunction->edgeDet.queJiao_RU_Open; + jiao_p_1 = cv::Point(roiMask.cols, 0); + jiao_p_2 = cv::Point(roiMask.cols, roiMask.rows); + } + + // 寻找轮廓 + vector> contours; + cv::findContours(roiMask, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); + + // 找到最大面积的轮廓 + double maxArea = -1; + int maxAreaIdx = -1; + for (size_t i = 0; i < contours.size(); ++i) + { + cv::Rect rect = cv::boundingRect(contours[i]); + cv::Point pc(rect.x + rect.width / 2, rect.y + rect.height / 2); + if (jiao_f_1) + { + // printf("1=%d =========== %d %d\n\n", type, abs(pc.x - jiao_p_1.x), abs(pc.y - jiao_p_1.y)); + if (abs(pc.x - jiao_p_1.x) < pDetConfig->pBaseCheckFunction->edgeDet.queJiao_width && abs(pc.y - jiao_p_1.y) < pDetConfig->pBaseCheckFunction->edgeDet.queJiao_height) + { + continue; + } + } + if (jiao_f_2) + { + // printf("2=%d============ %d %d\n\n", type, abs(pc.x - jiao_p_2.x), abs(pc.y - jiao_p_2.y)); + if (abs(pc.x - jiao_p_2.x) < pDetConfig->pBaseCheckFunction->edgeDet.queJiao_width && abs(pc.y - jiao_p_2.y) < pDetConfig->pBaseCheckFunction->edgeDet.queJiao_height) + { + continue; + } + } + + if (rect.width >= pedgeDet->QX_Widht_min && rect.width <= pedgeDet->QX_Widht_max && + rect.height >= pedgeDet->QX_Height_min && rect.height <= pedgeDet->QX_Height_max) + { + double area = contourArea(contours[i]); + QX_Result tem; + tem.roi_src.x = rect.x + DetRoi.x; + tem.roi_src.y = rect.y + DetRoi.y; + tem.roi_src.width = rect.width; + tem.roi_src.height = rect.height; + tem.area_pixel = area; + pDetConfig->qx_result.push_back(tem); + } + } + + // cv::imwrite("detimg.png", img(DetRoi)); + // cv::imwrite("detimg_mask.png", roiMask); + // getchar(); + return 0; +} + +int Edge_QX_Det::applyMaskInROI(const cv::Mat &grayImg, const Det_ROI_Config &config, cv::Mat &result, int threshold) +{ + // 1. 获取 ROI 区域图像(不 clone,只引用) + cv::Mat roiGray = grayImg(config.roi); + // cv::imwrite("roiGray.png", roiGray); + // 2. 二值化(用 compare 更快) + cv::Mat binary; + cv::compare(roiGray, threshold, binary, cv::CMP_LT); // binary = roiGray > 128 ? 255 : 0 + // cv::imwrite("binary.png", binary); + // 3. 构建局部坐标的多边形(避免每次 new) + std::vector localPts; + localPts.reserve(config.plist.size()); + for (const auto &pt : config.plist) + localPts.emplace_back(pt.x - config.roi.x, pt.y - config.roi.y); + + // 4. 快速创建 mask 并填充 + cv::Mat mask = cv::Mat::zeros(roiGray.size(), CV_8UC1); + cv::fillPoly(mask, std::vector>{localPts}, 255); + // cv::imwrite("mask.png", mask); + // 5. 应用 mask + result = cv::Mat::zeros(roiGray.size(), CV_8UC1); + binary.copyTo(result, mask); + // cv::imwrite("result.png", result); + + return 0; +} + +int Edge_QX_Det::Draw_Det(const cv::Mat &img, DetConfigResult *pDetConfig) +{ + Base_Function_Edge_Det *pedgeDet = &pDetConfig->pBaseCheckFunction->edgeDet; + if (pedgeDet->region.size() <= 2) + { + return 1; + } + float resize_fx = 0.4; + float resize_fy = 0.4; + int dest_width = img.cols * resize_fx; + int dest_height = img.rows * resize_fy; + + cv::Size sz; + sz.width = dest_width; + sz.height = dest_height; + pDetConfig->Det_region.clear(); + std::vector Det_resize_region; + for (const auto p : pedgeDet->region) + { + cv::Point pc; + if (pDetConfig->alginResult.H.empty()) + { + pc.x = p.x - pDetConfig->alginResult.corpRoi.x + pDetConfig->alginResult.offtx; + pc.y = p.y - pDetConfig->alginResult.corpRoi.y + pDetConfig->alginResult.offty; + } + else + { + cv::Point pt; + pt = CheckUtil::transformPoint(p, pDetConfig->alginResult.H); + pc.x = pt.x - pDetConfig->alginResult.corpRoi.x; + pc.y = pt.y - pDetConfig->alginResult.corpRoi.y; + } + + pDetConfig->Det_region.push_back(pc); + + cv::Point pcs; + pcs.x = pc.x * resize_fx; + pcs.y = pc.y * resize_fy; + Det_resize_region.push_back(pcs); + } + + cv::Mat detimg; + cv::resize(img, detimg, sz); + if (detimg.channels() != 1) + { + cv::cvtColor(detimg, detimg, cv::COLOR_RGB2GRAY); + } + cv::Mat mask = cv::Mat::zeros(detimg.size(), CV_8UC1); + + // 把 points 转成 std::vector> 格式 + std::vector> pts; + pts.push_back(Det_resize_region); + // 填充区域为 255 + cv::fillPoly(mask, pts, cv::Scalar(255)); + + cv::Mat binary; + cv::threshold(detimg, binary, pedgeDet->Det_threshold, 255, cv::THRESH_BINARY_INV); + + cv::Mat result = cv::Mat::zeros(binary.size(), CV_8UC1); + binary.copyTo(result, mask); + + // cv::imwrite(pDetConfig->strChannel + "draw_detimg.png", detimg); + // cv::imwrite(pDetConfig->strChannel + "draw_region.png", mask); + // cv::imwrite(pDetConfig->strChannel + "draw_binary.png", binary); + // cv::imwrite(pDetConfig->strChannel + "draw_result.png", result); + // getchar(); + + // 寻找轮廓 + vector> contours; + cv::findContours(result, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); + + // 找到最大面积的轮廓 + double maxArea = -1; + int maxAreaIdx = -1; + for (size_t i = 0; i < contours.size(); ++i) + { + cv::Rect rect = cv::boundingRect(contours[i]); + rect.x /= resize_fx; + rect.y /= resize_fy; + rect.width /= resize_fx; + rect.height /= resize_fy; + // CheckUtil::printROI(rect,"dfe"); + + if (rect.width >= pedgeDet->QX_Widht_min && rect.width <= pedgeDet->QX_Widht_max && + rect.height >= pedgeDet->QX_Height_min && rect.height <= pedgeDet->QX_Height_max) + { + double area = contourArea(contours[i]); + area /= resize_fx; + area /= resize_fy; + QX_Result tem; + tem.roi_src.x = rect.x; + tem.roi_src.y = rect.y; + tem.roi_src.width = rect.width; + tem.roi_src.height = rect.height; + tem.area_pixel = area; + pDetConfig->qx_result.push_back(tem); + } + else + { + // printf("================== size \n"); + } + } + + return 0; +} + +int Edge_QX_Det::UDNoiseEdgeDetect(cv::Mat img, int DirectSign, int Gate, int BorW, cv::Rect roi, int StepCount, int Limit) +{ + if (img.empty()) + { + return -11; + } + if (img.channels() != 1) + { + printf("*****************************channels\n"); + + return -12; + } + if (StepCount < 0 || StepCount >= roi.width) + { + printf("*****************************StepCount\n"); + + return -22; + } + std::vector data; + // cv::Mat showimg; + // cv::cvtColor(img, showimg, cv::COLOR_GRAY2BGR); + uchar *pdata = (uchar *)img.data; + + int sx = roi.x; + int ex = roi.x + roi.width; + int sy = roi.y; + int ey = roi.y + roi.height; + // 表示 反向搜索 + if (DirectSign < 0) + { + sy = roi.y + roi.height; + ey = roi.y; + } + int step = roi.width / StepCount; + int offt = 0; + int sumsite = 0; + int sumcount = 0; + // 表示搜索黑点 + if (BorW == 0) + { + } + else // 表示搜索白点 + { + for (int x = roi.x; x < ex; x = x + step) + { + + int ncount = 0; + int start = 0; + + for (int y = sy;; y = y + DirectSign) + { + if (DirectSign > 0 && y > ey) + { + break; + } + if (DirectSign < 0 && y < ey) + { + break; + } + int maxv = 0; + // 1、计算当前值是否 满足基本要求 + offt = y * img.cols + x; + maxv = pdata[offt]; + + if (maxv < 40) + { + for (int ix = -4; ix < 5; ix++) + { + int newx = x + ix; + if (newx < 0) + { + newx = 0; + } + if (newx > img.cols) + { + newx = img.cols; + } + + offt = y * img.cols + newx; + + if (pdata[offt] > maxv) + { + maxv = pdata[offt]; + } + } + } + + if (maxv > 40) + { + // 2、计算区域最大值 + for (int k = -4; k < 5; k++) + { + int newy = y + k; + if (newy < 0) + { + newy = 0; + } + if (newy >= img.rows) + { + newy = img.rows - 1; + } + + for (int ix = -4; ix < 5; ix++) + { + int newx = x + ix; + if (newx < 0) + { + newx = 0; + } + if (newx > img.cols) + { + newx = img.cols; + } + + offt = newy * img.cols + newx; + + if (pdata[offt] > maxv) + { + maxv = pdata[offt]; + } + } + + /* code */ + } + if (bshowimg) + { + cv::Rect roi; + roi.x = x - 2; + roi.width = 5; + if (roi.x < 0) + { + roi.x = 0; + } + int rdp = roi.x + roi.width; + if (rdp > showimg.cols) + { + rdp = showimg.cols; + } + roi.width = rdp - roi.x; + + roi.y = y - 2; + roi.height = 5; + if (roi.y < 0) + { + roi.y = 0; + } + rdp = roi.y + roi.height; + if (rdp > showimg.rows) + { + rdp = showimg.rows; + } + roi.height = rdp - roi.y; + cv::rectangle(showimg, roi, cv::Scalar(0, 0, 255)); + /* code */ + } + } + else + { + // if (start > 0) + // { + // printf("error p %d %d %d \n", x, y, maxv); + // /* code */ + // } + } + // 3、满足要求 记录 + if (maxv >= Gate) + { + ncount += 2; + if (start == 0) + { + start = y; + } + if (ncount > Limit) + { + break; + } + } + else + { + // if (maxv < 15) + // { + // ncount = 0; + // } + ncount--; + if (ncount < 0) + { + ncount = 0; + start = 0; + } + } + } + // 4、满足退出要求,就退出 + if (ncount > Limit) + { + sumcount++; + sumsite += start; + data.push_back(start); + + if (bshowimg && !showimg.empty()) + { + cv::Point p(x, start); + cv::circle(showimg, p, 13, cv::Scalar(0, 255, 0), 5); + // cv::imwrite("showimg.png", showimg); + // printf(">>>>>>>> %d %d \n",x,start); + // getchar(); + } + } + } + } + + if (sumcount <= 0) + { + return -3; + } + else + { + // 先剔除异常数据 + std::vector filteredData = removeOutliers123(data); + + if (bshowimg && !showimg.empty()) + { + + // for (int i = 0; i < data.size(); i++) + // { + // printf("%d %f \n ", i, data.at(i)); + // } + + // for (int i = 0; i < filteredData.size(); i++) + // { + // printf("%d %f \n ", i, filteredData.at(i)); + // } + } + sumsite = 0; + sumcount = 0; + int mean = 0; + for (int i = 0; i < filteredData.size(); i++) + { + sumsite += filteredData.at(i); + sumcount++; + } + if (sumcount > 0) + { + mean = sumsite / sumcount; + } + + mean = sumsite / sumcount; + return mean; + } + + return -5; +} + +int Edge_QX_Det::LRNoiseEdgeDetect(cv::Mat img, int DirectSign, int Gate, int BorW, cv::Rect roi, int StepCount, int Limit) +{ + + if (img.empty()) + { + return -1; + } + if (img.channels() != 1) + { + printf("*****************************channels\n"); + + return -1; + } + if (StepCount < 0 || StepCount >= roi.width) + { + printf("*****************************StepCount\n"); + + return -2; + } + + std::vector data; + // cv::Mat showimg; + // cv::cvtColor(img, showimg, cv::COLOR_GRAY2BGR); + uchar *pdata = (uchar *)img.data; + + int sx = roi.x; + int ex = roi.x + roi.width; + int sy = roi.y; + int ey = roi.y + roi.height; + // 表示 反向搜索 + if (DirectSign < 0) + { + sx = roi.x + roi.width; + ex = roi.x; + } + int step = roi.height / StepCount; + int offt = 0; + int sumsite = 0; + int sumcount = 0; + // 表示搜索黑点 + if (BorW == 0) + { + } + else // 表示搜索白点 + { + // printf("---- y sy %d ey %d sx %d ex %d\n", sy, ey, sx, ex); + for (int y = sy; y < ey; y = y + step) + { + int ncount = 0; + int start = 0; + + for (int x = sx;; x = x + DirectSign) + { + if (DirectSign > 0 && x > ex) + { + break; + } + if (DirectSign < 0 && x < ex) + { + break; + } + int maxv = 0; + // 1、计算当前值是否 满足基本要求 + offt = y * img.cols + x; + maxv = pdata[offt]; + if (maxv < 40) + { + for (int k = -4; k < 5; k++) + { + int newy = y + k; + if (newy < 0) + { + newy = 0; + } + if (newy >= img.rows) + { + newy = img.rows - 1; + } + offt = newy * img.cols + x; + maxv = pdata[offt]; + if (pdata[offt] > maxv) + { + maxv = pdata[offt]; + } + } + } + + if (maxv > 40) + { + // 2、计算区域最大值 + for (int k = -4; k < 5; k++) + { + int newy = y + k; + if (newy < 0) + { + newy = 0; + } + if (newy >= img.rows) + { + newy = img.rows - 1; + } + + for (int ix = -4; ix < 5; ix++) + { + int newx = x + ix; + if (newx < 0) + { + newx = 0; + } + if (newx > img.cols) + { + newx = img.cols; + } + + offt = newy * img.cols + newx; + + if (pdata[offt] > maxv) + { + maxv = pdata[offt]; + } + } + + /* code */ + } + if (bshowimg) + { + cv::Rect roi; + roi.x = x - 2; + roi.width = 5; + if (roi.x < 0) + { + roi.x = 0; + } + int rdp = roi.x + roi.width; + if (rdp > showimg.cols) + { + rdp = showimg.cols; + } + roi.width = rdp - roi.x; + + roi.y = y - 2; + roi.height = 5; + if (roi.y < 0) + { + roi.y = 0; + } + rdp = roi.y + roi.height; + if (rdp > showimg.rows) + { + rdp = showimg.rows; + } + roi.height = rdp - roi.y; + cv::rectangle(showimg, roi, cv::Scalar(0, 0, 255)); + /* code */ + } + } + else + { + // if (start > 0) + // { + // //printf("error p %d %d %d \n", x, y, maxv); + // /* code */ + // } + } + // 3、满足要求 记录 + + if (maxv >= Gate) + { + ncount += 2; + if (start == 0) + { + start = x; + // printf("---- %d %d y %d\n", pdata[offt], start, y); + } + if (ncount > Limit) + { + break; + } + } + else + { + // if (maxv < 15) + // { + // ncount = 0; + // } + ncount--; + if (ncount < 0) + { + start = 0; + ncount = 0; + } + } + } + if (ncount > Limit) + { + sumcount++; + sumsite += start; + data.push_back(start); + if (bshowimg && !showimg.empty()) + { + cv::Point p(start, y); + cv::circle(showimg, p, 13, cv::Scalar(255, 255, 125), 5); + // cv::imwrite("showimg.png", showimg); + // printf(">>>>>>>>\n"); + // getchar(); + } + } + } + } + + // if (bshowimg && !showimg.empty()) + // { + // cv::imwrite("showimg.png", showimg); + // printf(">>>>>>123>> DirectSign %d \n",DirectSign); + // getchar(); + // } + // if (DirectSign < 0) + // { + + // cv::imwrite("showimg.png", img); + // printf(">>>>>>>>\n"); + // getchar(); + // } + if (sumcount <= 0) + { + return -3; + } + else + { + + // 先剔除异常数据 + std::vector filteredData = removeOutliers123(data); + + if (bshowimg && !showimg.empty()) + { + + // for (int i = 0; i < data.size(); i++) + // { + // printf("%d %f \n ", i, data.at(i)); + // } + + // for (int i = 0; i < filteredData.size(); i++) + // { + // printf("%d %f \n ", i, filteredData.at(i)); + // } + } + sumsite = 0; + sumcount = 0; + int mean = 0; + for (int i = 0; i < filteredData.size(); i++) + { + sumsite += filteredData.at(i); + sumcount++; + } + if (sumcount > 0) + { + mean = sumsite / sumcount; + } + + mean = sumsite / sumcount; + return mean; + } + + return -5; +} diff --git a/AlgorithmModule/src/ImageAllResult.cpp b/AlgorithmModule/src/ImageAllResult.cpp new file mode 100644 index 0000000..392a266 --- /dev/null +++ b/AlgorithmModule/src/ImageAllResult.cpp @@ -0,0 +1,117 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-09-13 20:39:37 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-23 14:29:12 + * @FilePath: /BOE_CELL_AOI_Detect/AlgorithmModule/src/CameraResult.cpp + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#include "ImageAllResult.h" + +ImageAllResult::ImageAllResult() +{ + detlog = std::make_shared(); + pDetResult = std::make_shared(); +} + +ImageAllResult::~ImageAllResult() +{ +} + +void ImageAllResult::AddLog(std::string str) +{ + LogList.push_back(str); +} +ImageAllResult::DetStep ImageAllResult::getStep() +{ + std::lock_guard lock_cam(mtx_Det); + return m_step; +} +void ImageAllResult::setStep(DetStep step) +{ + std::lock_guard lock_cam(mtx_Det); + m_step = step; +} + +bool ImageAllResult::IsNotDet() +{ + std::lock_guard lock_cam(mtx_Det); + if (m_step == DetStep_NotDet) + { + return true; + } + + return false; +} + +int ImageAllResult::AddDetImage(std::shared_ptr p) +{ + { + std::lock_guard lock_cam(mtx_Det); + result = std::make_shared(); + p->time_PushIn = CheckUtil::getcurTime(); + result->in_shareImage = p; + result->checkStatus = 1; + result->nDetStep = 0; + result->nresult = -1; + result->basicResult.img_id = p->img_id; + result->basicResult.imgtype = p->imgtype; + result->basicResult.imgstr = p->imgstr; + result->basicResult.strChannel = p->strChannel; + + strChannel = p->strChannel; + strBaseInfo = productBaseResult->strproductName + " cam " + cameraBaseResult->strCameraName + " channel " + strChannel; + + if (p->Det_Mode == DET_MODE_ReJson) + { + m_CheckResultJson.GetConfig(p->resultJson, pDetResult); + + fscale_detToresult_x = 1; + fscale_detToresult_y = 1; + // 图片 + if (!p->img.empty()) + { + detImg = p->img; + /* code */ + } + else + { + if (pDetResult->CutRoi.width > 0 && pDetResult->CutRoi.height > 0) + { + detImg = cv::Mat::zeros(pDetResult->CutRoi.height, pDetResult->CutRoi.width, CV_8UC1); + } + else + { + detImg = cv::Mat::zeros(1000, 2000, CV_8UC1); + } + } + + { + + cv::Size sz; + sz.width = RESIZE_IMAGE_WIDTH; + + float fw = RESIZE_IMAGE_WIDTH * 1.0f / detImg.cols; + sz.height = int(detImg.rows * fw); + + cv::resize(detImg, resultImg, sz); + if (resultImg.channels() == 1) + { + cv::cvtColor(resultImg, resultImg, cv::COLOR_GRAY2BGR); + } + + result->resultimg = resultImg; + + result->cutSrcimg = detImg; + + fscale_detToresult_x = resultImg.cols * 1.0f / detImg.cols; + fscale_detToresult_y = resultImg.rows * 1.0f / detImg.rows; + } + + // pDetResult->print("result"); + // getchar(); + } + } + + return 0; +} diff --git a/AlgorithmModule/src/ImageDetBase.cpp b/AlgorithmModule/src/ImageDetBase.cpp new file mode 100644 index 0000000..f1d624a --- /dev/null +++ b/AlgorithmModule/src/ImageDetBase.cpp @@ -0,0 +1,14 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:50:00 + * @LastEditTime: 2022-09-26 16:27:27 + * @LastEditors: sueRimn + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/src/CamDeal.cpp + */ +#include "ImageDetBase.h" +#include "ImgCheckAnalysisy.hpp" +ImgCheckBase *ImgCheckBase::GetInstance() +{ + return (ImgCheckBase *)new ImgCheckAnalysisy(); +} diff --git a/AlgorithmModule/src/ImageResultJudge.cpp b/AlgorithmModule/src/ImageResultJudge.cpp new file mode 100644 index 0000000..00c68f6 --- /dev/null +++ b/AlgorithmModule/src/ImageResultJudge.cpp @@ -0,0 +1,1233 @@ + +#include "ImageResultJudge.h" + +ImageResultJudge::ImageResultJudge(/* args */) +{ + m_pCommonAnalysisyConfig = NULL; + ptr_thread_Draw = NULL; + + m_bExit = false; +} + +ImageResultJudge::~ImageResultJudge() +{ +} + +int ImageResultJudge::SetAnalysisyConfig(AnalysisyConfigST *pAnalysisyConfig) +{ + m_pAnalysisyConfig = pAnalysisyConfig; + m_pChannelFuntion = &m_pAnalysisyConfig->checkFunction; + m_pbaseCheckFunction = &m_pAnalysisyConfig->baseFunction; + return 0; +} + +cv::Rect ImageResultJudge::GetCutRoi(cv::Rect &roi, const cv::Mat &img) +{ + + cv::Rect cutroi; + int pc_x = roi.x + roi.width * 0.5; + int pc_y = roi.y + roi.height * 0.5; + bool bresize = false; + if (roi.width < QX_SAMLLIMG_WIDTH && roi.height < QX_SAMLLIMG_HEIGHT) + { + cutroi.width = QX_SAMLLIMG_WIDTH; + cutroi.x = pc_x - QX_SAMLLIMG_WIDTH * 0.5; + cutroi.height = QX_SAMLLIMG_HEIGHT; + cutroi.y = pc_y - QX_SAMLLIMG_HEIGHT * 0.5; + } + else + { + // 宽 高 + if (roi.width > roi.height) + { + cutroi.width = roi.width + 20; + cutroi.x = roi.x - 10; + + float fsx = QX_SAMLLIMG_HEIGHT * 1.0f / QX_SAMLLIMG_WIDTH; + cutroi.height = cutroi.width * fsx; + cutroi.y = pc_y - cutroi.height * 0.5; + } + else + { + cutroi.height = roi.height + 20; + cutroi.y = roi.y - 10; + + float fsy = QX_SAMLLIMG_WIDTH * 1.0f / QX_SAMLLIMG_HEIGHT; + cutroi.width = cutroi.height * fsy; + cutroi.x = pc_x - cutroi.width * 0.5; + } + + bresize = true; + } + + if (cutroi.x < 0) + { + cutroi.x = 0; + } + if (cutroi.y < 0) + { + cutroi.y = 0; + } + if (cutroi.x + cutroi.width >= img.cols) + { + cutroi.x = img.cols - cutroi.width; + if (cutroi.x < 0) + { + cutroi.x = 0; + if (cutroi.x + cutroi.width >= img.cols) + { + cutroi.width = img.cols; + } + } + } + if (cutroi.y + cutroi.height >= img.rows) + { + cutroi.y = img.rows - cutroi.height; + if (cutroi.y < 0) + { + cutroi.y = 0; + if (cutroi.y + cutroi.height >= img.rows) + { + cutroi.height = img.rows; + } + } + } + + return cutroi; +} +int ImageResultJudge::GetAIDetImg(std::shared_ptr pImageResult, cv::Point pcenter, cv::Mat &AI_InImg, cv::Mat &AI_OutImg) +{ + + // printf("%d %d \n", pcenter.x, pcenter.y); + // int AINum = pImageResult->AI_Qx_MaskList.size(); + for (auto &pAIMask : pImageResult->AI_Qx_MaskList) + { + cv::Rect roi = pAIMask->roi; + + if (pcenter.x >= roi.x && pcenter.x <= (roi.x + roi.width) && + pcenter.y >= roi.y && pcenter.y <= (roi.y + roi.height)) + { + // printf("%d %d %d %d \n", roi.x, roi.y, roi.width, roi.height); + // 点 (x, y) 在矩形区域内 + // printf("--------------------------\n"); + AI_InImg = pAIMask->AI_inImg; + AI_OutImg = pAIMask->AI_mask; + } + } + return 0; +} +int ImageResultJudge::UpdateImgageScale() +{ + + if (m_pBasicConfig->fImage_Scale_x > 0 && m_pBasicConfig->fImage_Scale_x < 1 && + m_pBasicConfig->fImage_Scale_y > 0 && m_pBasicConfig->fImage_Scale_y < 1) + { + + m_fImgage_Scale_X = m_pBasicConfig->fImage_Scale_x; + m_fImgage_Scale_Y = m_pBasicConfig->fImage_Scale_y; + } + + return 0; +} +int ImageResultJudge::ResultJudge(std::shared_ptr pImageResult) +{ + std::shared_ptr pImageLog = pImageResult->detlog; + int regionNum = m_pCommonAnalysisyConfig->regionConfigArr.size(); + if (regionNum <= 0) + { + return 1; + } + + pImageLog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Param Judge", "img %s ====================start regon num %d", pImageResult->strChannel.c_str(), regionNum); + + float fs_resize_x = pImageResult->fscale_detToresult_x; + float fs_resize_y = pImageResult->fscale_detToresult_x; + + std::shared_ptr pDetResult = pImageResult->pDetResult; // 检测结果 + std::shared_ptr m_CheckResult_shareP = pImageResult->result; // 返回结果 + int qxNum = pDetResult->pQx_ErrorList->size(); + + // map> allQxZoning; + + map> allQxZoning; + set qx_name_list; + + for (int qxidx = 0; qxidx < qxNum; qxidx++) + { + QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx); + std::shared_ptr pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog; + // pQxLog->bPrintStr = true; + cv::Rect roi = QX_info->roi; + float JudgArea = QX_info->JudgArea; + float JudgArea_second = QX_info->JudgArea_second; + float flen = QX_info->flen; + float fbreadth = QX_info->fbreadth; + float grayDis = QX_info->grayDis; + int energy = QX_info->energy; + float fupS = QX_info->fUpIou; + int maxValue = QX_info->maxValue; + float density = QX_info->density; + int QX_whiteBLACK = QX_info->whiteOrBlack; + int config_qx_type = QX_info->nconfig_qx_type; + std::string qx_name = CONFIG_QX_NAME_Names[config_qx_type]; + std::string qx_wb = WHITE_BLCAK_Names[QX_whiteBLACK]; + + pQxLog->AddCheckstr(PrintLevel_1, + "", "qxidx: %d roi[%d %d %d %d] qx %d %s %s JudgArea %f hj %f len %f breadth %f energy %d region num %ld", + qxidx, roi.x, roi.y, roi.width, roi.height, config_qx_type, qx_name.c_str(), qx_wb.c_str(), + JudgArea, grayDis, flen, fbreadth, energy, QX_info->detRegionidxList.size()); + + cv::Point pCenter; + pCenter.x = roi.x + roi.width * 0.5; + pCenter.y = roi.y + roi.height * 0.5; + + bool bNG_Status = false; + bool bYS_Status = false; + bool Judge_Status = false; + + QX_info->result = QX_RESULT_TYPE_NoJduge; + + allQxZoning[qx_name].reserve(20); + qx_name_list.insert(qx_name); + + // 遍历当前区域所属的 区域进行参数判断。 + for (auto iregion : QX_info->detRegionidxList) + { + pQxLog->AddCheckstr(PrintLevel_2, "QX info", ">>>>>>>> region %d ", + iregion + 1); + + // 1、判断当前区域是否要检测该通道画面。 + + // 2、基础的参数判断 + if (iregion >= regionNum) + { + pQxLog->AddCheckstr(PrintLevel_3, "QX info", "Error regionIdx %d > param size %d ", + iregion, regionNum); + addInDrawBlob(config_qx_type, qxidx, QX_info, fs_resize_x, fs_resize_y); + continue; + } + if (config_qx_type >= CONFIG_QX_NAME_count || config_qx_type < 0) + { + pQxLog->AddCheckstr(PrintLevel_3, "QX info", "Error def_type %d size %d ", + config_qx_type, CONFIG_QX_NAME_count); + addInDrawBlob(config_qx_type, qxidx, QX_info, fs_resize_x, fs_resize_y); + continue; + } + int paramIdx = m_QxInParamListIdx[config_qx_type]; + if (paramIdx < 0) + { + pQxLog->AddCheckstr(PrintLevel_3, "qx error", " paramIdx < 0 "); + addInDrawBlob(config_qx_type, qxidx, QX_info, fs_resize_x, fs_resize_y); + continue; + } + + // 3、 基本参数判断 + int checkFlage = 0; + int nerrortype = 0; + for (int ict = 0; ict < ANALYSIS_TYPE_COUNT; ict++) + { + + std::string str_checkflag = "QX-check"; + checkFlage = ict; + if (ict == ANALYSIS_TYPE_YS) + { + str_checkflag = "YS-check"; + } + // pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "qx judge", " %s start", str_checkflag.c_str()); + + CheckConfig_Regions_Param *pParam = &m_pCommonAnalysisyConfig->regionConfigArr.at(iregion).checkConfig_Regions_type[ict].checkConfig_Regions_Param.at(paramIdx); + + bool bUse = false; + + for (int j = 0; j < pParam->useNum; j++) + { + + bool result = true; + if (!pParam->paramArr[j].bEnable) + { + // pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "error ", "param is CLosed"); + continue; + } + + bUse = true; + float At = pParam->paramArr[j].area; + float Et = pParam->paramArr[j].energy; + float hj = pParam->paramArr[j].hj; + float Len = pParam->paramArr[j].length; + float Breadth = pParam->paramArr[j].breadth; + float md = pParam->paramArr[j].density; + float dis = pParam->paramArr[j].dis; + float num = pParam->paramArr[j].num; + + if(dis > 0 && num > 0 && allQxZoning[qx_name].size() == 0){ + pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "Dis | Num", "qx_name : %s, dis : %f, num : %f, scale_X : %f, scale_Y : %f", + qx_name.c_str(), dis, num, m_fImgage_Scale_X, m_fImgage_Scale_Y); + singleQxZoningInfo singleQxZoningInfoTemp; + singleQxZoningInfoTemp.Init(); + singleQxZoningInfoTemp.judge_dis = dis; + singleQxZoningInfoTemp.judge_num = num; + singleQxZoningInfoTemp.scale_X = m_fImgage_Scale_X; + singleQxZoningInfoTemp.scale_Y = m_fImgage_Scale_Y; + allQxZoning[qx_name].push_back(singleQxZoningInfoTemp); + } + + // 黑缺陷 + if (QX_whiteBLACK == CONFIG_QX_WHITE) + { + // pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "param---", "qx :white"); + if (hj >= 0 || Et >= 0) + { + pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "param ", "Error param idx %d / %d qx white hj %f and energ %f >0", + j + 1, pParam->useNum, hj, Et); + continue; + } + Et = std::abs(Et); + hj = std::abs(hj); + } + else + { + // pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "param---", "qx :blcak"); + if (hj < 0 || Et < 0) + { + pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "param ", "Error param idx %d / %d qx blcak hj %f and energ %f < 0", + j + 1, pParam->useNum, hj, Et); + continue; + } + } + Judge_Status = true; + + float detArea = JudgArea; + + if (energy >= Et && + detArea >= At && + grayDis >= hj && + flen >= Len && + fbreadth >= Breadth) + { + nerrortype = 1; + result = false; + if (ict == ANALYSIS_TYPE_YS) + { + bYS_Status = true; + } + else + { + bNG_Status = true; + } + } + if (!result) + { + pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "result", "%s param idx %d / %d parma A %f E %f HJ %f L %f B %f", + BOOL_TO_STROK(result), j + 1, pParam->useNum, At, Et, hj, Len, Breadth); + } + else + { + pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "result", "%s param idx %d / %d", BOOL_TO_STROK(result), j + 1, pParam->useNum); + } + + if (detArea < At) + { + pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "Area", "%s -> %f %s %f ", + BOOL_TO_STR(detArea >= At), detArea, BOOL_TO_ThanLess(detArea >= At), At); + } + if (energy < Et) + { + pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "Energy", "%s -> %d %s %f ", + BOOL_TO_STR(energy >= Et), energy, BOOL_TO_ThanLess(energy >= Et), Et); + } + if (grayDis < hj) + { + pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "HJ", "%s -> %f %s %f ", + BOOL_TO_STR(grayDis >= hj), grayDis, BOOL_TO_ThanLess(grayDis > hj), hj); + } + if (flen < Len) + { + pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "Len", "%s -> %f %s %f ", + BOOL_TO_STR(flen >= Len), flen, BOOL_TO_ThanLess(flen > Len), Len); + } + if (fbreadth < Breadth) + { + pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "Breadth", "%s -> %f %s %f ", + BOOL_TO_STR(fbreadth >= Breadth), fbreadth, BOOL_TO_ThanLess(fbreadth > Breadth), Breadth); + } + + if (!result) + { + break; + } + } + if (!bUse) + { + pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "info", "Not Use Param Judge"); + } + + if (nerrortype != 0) + { + pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "info", " %s end result: erorr type %s", str_checkflag.c_str(), qx_name.c_str()); + break; + } + else + { + pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "info", " %s end result: OK ", str_checkflag.c_str()); + } + } + + // 已经NG 就不继续判断了。 + if (bNG_Status) + { + break; + } + } + + std::string resultType = "OK"; + + if (!Judge_Status) + { + QX_info->result = QX_RESULT_TYPE_NoJduge; + } + else + { + if (bNG_Status) + { + QX_info->result = QX_RESULT_TYPE_NG; + } + else if (bYS_Status) + { + QX_info->result = QX_RESULT_TYPE_YS; + int if_insert = false; + singleQxInfo current_YS_info(qxidx, QX_RESULT_TYPE_YS, pCenter); + for(int i = 0; i < allQxZoning[qx_name].size(); i++){ + if(allQxZoning[qx_name][i].Insert(current_YS_info)){ + if_insert = true; + break; + } + } + if(!if_insert && allQxZoning[qx_name].size() > 0){ + singleQxZoningInfo newZoningInfoTemp; + newZoningInfoTemp.Init(); + newZoningInfoTemp.judge_dis = allQxZoning[qx_name][0].judge_dis; + newZoningInfoTemp.judge_num = allQxZoning[qx_name][0].judge_num; + newZoningInfoTemp.center = pCenter; + newZoningInfoTemp.scale_X = m_fImgage_Scale_X; + newZoningInfoTemp.scale_Y = m_fImgage_Scale_Y; + newZoningInfoTemp.qxList.push_back(current_YS_info); + allQxZoning[qx_name].push_back(newZoningInfoTemp); // 插入失败,添加一个新分组 + } + } + else + { + QX_info->result = QX_RESULT_TYPE_OK; + } + } + QX_info->result_name = QX_RESULT_TYPE_Names[QX_info->result]; + resultType = QX_info->result_name; + + pQxLog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "10、Param Judge", "qx %s ,result = %s", qx_name.c_str(), resultType.c_str()); + + // 当前是好品 + if (!bNG_Status) + { + // 大缺陷判断 + if (m_pbaseCheckFunction->bigNG.bOpen) + { + bool berror = false; + if (config_qx_type >= 0 || config_qx_type < CONFIG_QX_NAME_count) + { + bool qx_config_open = m_pbaseCheckFunction->bigNG.qx[config_qx_type].bOpen; + float qx_config_area = m_pbaseCheckFunction->bigNG.qx[config_qx_type].fArea; + if (qx_config_open) + { + if (JudgArea > qx_config_area) + { + berror = true; + bNG_Status = true; + } + pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "Big QX single result ", "%s ", BOOL_TO_STROK(!berror)); + pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "Area", "%s -> %f %s %f ", + BOOL_TO_STR(JudgArea > qx_config_area), JudgArea, BOOL_TO_ThanLess(JudgArea > qx_config_area), qx_config_area); + } + else + { + pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, " big qx", "qx %s param close ", m_pbaseCheckFunction->bigNG.qx[config_qx_type].strname.c_str()); + } + } + } + else + { + pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, " big qx", " param close "); + } + + if (!Judge_Status) + { + QX_info->result = QX_RESULT_TYPE_NoJduge; + } + else + { + if (bNG_Status) + { + QX_info->result = QX_RESULT_TYPE_NG; + } + else if (bYS_Status) + { + QX_info->result = QX_RESULT_TYPE_YS; + } + else + { + QX_info->result = QX_RESULT_TYPE_OK; + } + } + QX_info->result_name = QX_RESULT_TYPE_Names[QX_info->result]; + resultType = QX_info->result_name; + + pQxLog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "12、big qx ", "qx %s ,result = %s", qx_name.c_str(), resultType.c_str()); + } + + if (bNG_Status) + { + m_CheckResult_shareP->nresult = 1; + } + if (bYS_Status) + { + m_CheckResult_shareP->nYS_result = 1; + } + + m_CheckResult_shareP->checkStatus = 0; + // 生成缺陷小图 + if (bYS_Status || bNG_Status) + { + + // 生成图片 + QXImageResult tem; + tem.idx = qxidx; + cv::Rect CutRoi = GetCutRoi(roi, pImageResult->detImg); + // CheckUtil::printROI(CutRoi, "CutRoi"); + cv::Size sz = cv::Size(QX_SAMLLIMG_WIDTH, QX_SAMLLIMG_HEIGHT); + + if (pImageResult->detImg.channels() == 1) + { + cv::cvtColor(pImageResult->detImg(CutRoi), tem.srcImg, cv::COLOR_GRAY2BGR); + } + else + { + tem.srcImg = pImageResult->detImg(CutRoi).clone(); + } + cv::resize(tem.srcImg, tem.resizeImg, sz); + + int nqx_type = ConfigTypeToResultType(config_qx_type); + tem.type = nqx_type; + tem.area = JudgArea; + tem.energy = energy; + tem.hj = grayDis; + tem.max_v = maxValue; + tem.strTypeName = QX_Result_Names[nqx_type]; + tem.qx_Code = QX_Result_Code[nqx_type]; + tem.srcImgroi = roi; + tem.srcImgroi.x += pDetResult->CutRoi.x; + tem.srcImgroi.y += pDetResult->CutRoi.y; + tem.len = flen; + tem.breadth = fbreadth; + tem.qx_type = 0; + tem.fScore = 0; + tem.density = 0; + + tem.resizeImgroi.x = roi.x * fs_resize_x; + tem.resizeImgroi.width = roi.width * fs_resize_x; + tem.resizeImgroi.y = roi.y * fs_resize_y; + tem.resizeImgroi.height = roi.height * fs_resize_y; + + tem.x_pixel = roi.x + roi.width * 0.5; + tem.y_pixel = roi.y + roi.height * 0.5; + + tem.x_mm = tem.x_pixel * m_fImgage_Scale_X; + tem.y_mm = tem.y_pixel * m_fImgage_Scale_Y; + + tem.CutImgroi = roi; + tem.CutImgroi.x -= CutRoi.x; + tem.CutImgroi.y -= CutRoi.y; + + if (bNG_Status) + { + + m_CheckResult_shareP->defectResultList[nqx_type].nresult = 1; + m_CheckResult_shareP->defectResultList[nqx_type].keyName = QX_Result_Names[nqx_type]; + m_CheckResult_shareP->defectResultList[nqx_type].keyCode = QX_Result_Code[nqx_type]; + m_CheckResult_shareP->defectResultList[nqx_type].num++; + if (m_CheckResult_shareP->nresult <= ERROR_TYPE_OK) + { + m_CheckResult_shareP->nresult = nqx_type; + } + + GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img); + m_CheckResult_shareP->qxImageResult.push_back(tem); + pQxLog->bPrintStr = true; + pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, " result ", " ---name: %s ---code: %s ---srcImgroi.x: %d ---srcImgroi.y: %d\n", tem.strTypeName.c_str(), tem.qx_Code.c_str(), tem.srcImgroi.x, tem.srcImgroi.y); + pQxLog->bPrintStr = false; + } + else + { + + if (m_CheckResult_shareP->nYS_result <= ERROR_TYPE_OK) + { + m_CheckResult_shareP->nYS_result = nqx_type; + } + + GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img); + + m_CheckResult_shareP->YS_ImageResult.push_back(tem); + } + } + } + + for (const auto& name : qx_name_list) + { + string qx_name = name; + for(int i = 0; i < allQxZoning[qx_name].size(); i++) + { + // 个数超过设定值,YS改为NG + if(allQxZoning[qx_name][i].judgeNum()){ + for(int j = 0; j < allQxZoning[qx_name][i].qxList.size(); j++) + { + int qxidx = allQxZoning[qx_name][i].qxList[j].qxidx; + cv::Point pCenter = allQxZoning[qx_name][i].qxList[j].pcenter; + QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx); + std::shared_ptr pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog; + + pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "YS to NG", " name: %s, idx: %d | Index %d / %d > %d", qx_name.c_str(), qxidx, j + 1, allQxZoning[qx_name][i].qxList.size(), allQxZoning[qx_name][i].judge_num); + + // pQxLog->bPrintStr = true; + cv::Rect roi = QX_info->roi; + float JudgArea = QX_info->JudgArea; + float JudgArea_second = QX_info->JudgArea_second; + float flen = QX_info->flen; + float fbreadth = QX_info->fbreadth; + float grayDis = QX_info->grayDis; + int energy = QX_info->energy; + float fupS = QX_info->fUpIou; + int maxValue = QX_info->maxValue; + float density = QX_info->density; + int QX_whiteBLACK = QX_info->whiteOrBlack; + int config_qx_type = QX_info->nconfig_qx_type; + std::string qx_name = CONFIG_QX_NAME_Names[config_qx_type]; + std::string qx_wb = WHITE_BLCAK_Names[QX_whiteBLACK]; + + QX_info->result = QX_RESULT_TYPE_NG; + QX_info->result_name = QX_RESULT_TYPE_Names[QX_info->result]; + std::string resultType = QX_info->result_name; + m_CheckResult_shareP->nresult = 1; + + // 生成图片 + QXImageResult tem; + tem.idx = qxidx; + cv::Rect CutRoi = GetCutRoi(roi, pImageResult->detImg); + // CheckUtil::printROI(CutRoi, "CutRoi"); + cv::Size sz = cv::Size(QX_SAMLLIMG_WIDTH, QX_SAMLLIMG_HEIGHT); + + if (pImageResult->detImg.channels() == 1) + { + cv::cvtColor(pImageResult->detImg(CutRoi), tem.srcImg, cv::COLOR_GRAY2BGR); + } + else + { + tem.srcImg = pImageResult->detImg(CutRoi).clone(); + } + cv::resize(tem.srcImg, tem.resizeImg, sz); + + int nqx_type = ConfigTypeToResultType(config_qx_type); + tem.type = nqx_type; + tem.area = JudgArea; + tem.energy = energy; + tem.hj = grayDis; + tem.max_v = maxValue; + tem.strTypeName = QX_Result_Names[nqx_type]; + tem.qx_Code = QX_Result_Code[nqx_type]; + tem.srcImgroi = roi; + tem.srcImgroi.x += pDetResult->CutRoi.x; + tem.srcImgroi.y += pDetResult->CutRoi.y; + tem.len = flen; + tem.breadth = fbreadth; + tem.qx_type = 0; + tem.fScore = 0; + tem.density = 0; + + tem.resizeImgroi.x = roi.x * fs_resize_x; + tem.resizeImgroi.width = roi.width * fs_resize_x; + tem.resizeImgroi.y = roi.y * fs_resize_y; + tem.resizeImgroi.height = roi.height * fs_resize_y; + + tem.x_pixel = roi.x + roi.width * 0.5; + tem.y_pixel = roi.y + roi.height * 0.5; + + tem.x_mm = tem.x_pixel * m_fImgage_Scale_X; + tem.y_mm = tem.y_pixel * m_fImgage_Scale_Y; + + tem.CutImgroi = roi; + tem.CutImgroi.x -= CutRoi.x; + tem.CutImgroi.y -= CutRoi.y; + + m_CheckResult_shareP->defectResultList[nqx_type].nresult = 1; + m_CheckResult_shareP->defectResultList[nqx_type].keyName = QX_Result_Names[nqx_type]; + m_CheckResult_shareP->defectResultList[nqx_type].keyCode = QX_Result_Code[nqx_type]; + m_CheckResult_shareP->defectResultList[nqx_type].num++; + if (m_CheckResult_shareP->nresult <= ERROR_TYPE_OK) + { + m_CheckResult_shareP->nresult = nqx_type; + } + + GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img); + m_CheckResult_shareP->qxImageResult.push_back(tem); + } + } + } + + } + + for (int qxidx = 0; qxidx < qxNum; qxidx++) + { + + QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx); + switch (QX_info->result) + { + case QX_RESULT_TYPE_OK: + pImageResult->Ok_num++; + break; + case QX_RESULT_TYPE_NG: + pImageResult->NG_num++; + break; + case QX_RESULT_TYPE_YS: + pImageResult->YS_num++; + break; + case QX_RESULT_TYPE_NoJduge: + pImageResult->NoJudge_num++; + break; + default: + pImageResult->NoJudge_num++; + break; + } + } + + pImageLog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Param Judge", "img %s ====================End ng %d ys %d ok %d nojudge %d ", + pImageResult->strChannel.c_str(), pImageResult->NG_num, pImageResult->YS_num, pImageResult->Ok_num, pImageResult->NoJudge_num); + + return 0; +} + +int ImageResultJudge::UpdateConfig() +{ + if (m_pAnalysisyConfig->commonCheckConfig.nodeConfigArr.size() > 0) + { + m_pCommonAnalysisyConfig = &m_pAnalysisyConfig->commonCheckConfig.nodeConfigArr.at(0); + m_pRegionAnalysisyParam = &m_pCommonAnalysisyConfig->regionConfigArr.at(0); + m_pBasicConfig = &m_pAnalysisyConfig->commonCheckConfig.baseConfig; + } + else + { + m_pCommonAnalysisyConfig = NULL; + } + + GetParamidx(); + UpdateImgageScale(); + return 0; +} + +int ImageResultJudge::DrawResult(std::shared_ptr pImageResult) +{ + std::shared_ptr txtbackgroundk = std::make_shared(); + if (!ptr_thread_Draw) + { + ptr_thread_Draw = std::make_shared(std::bind(&ImageResultJudge::ThreadDraw, this)); + } + + float fs_resize_x = pImageResult->fscale_detToresult_x; + float fs_resize_y = pImageResult->fscale_detToresult_x; + + std::shared_ptr m_CheckResult_shareP = pImageResult->result; // 返回结果 + std::vector m_drawList; + if (m_CheckResult_shareP->resultimg.empty()) + { + return 0; + } + + cv::Scalar color_NG = cv::Scalar(0, 0, 255); + cv::Scalar color_Ys = cv::Scalar(0, 255, 255); + cv::Scalar color_Nojudge = cv::Scalar(0, 255, 0); + + long t1 = CheckUtil::getcurTime(); + for (int i = 0; i < m_CheckResult_shareP->qxImageResult.size(); i++) + { + std::shared_ptr draw_qx = std::make_shared(); + + QXImageResult *pqx = &m_CheckResult_shareP->qxImageResult.at(i); + cv::Rect drawroi = pqx->resizeImgroi; + + cv::Point cp = cv::Point(drawroi.x + drawroi.width * .5, drawroi.y + drawroi.height * 0.5); + int r = drawroi.width; + if (drawroi.height > r) + { + r = drawroi.height; + } + r += 10; + draw_qx->dr = r; + draw_qx->cp = cp; + draw_qx->color = color_NG; + draw_qx->drawImg = m_CheckResult_shareP->resultimg; + draw_qx->type = Draw_circle; + sendTask(draw_qx); + + std::shared_ptr draw_str = std::make_shared(); + draw_str->drawImg = m_CheckResult_shareP->resultimg; + draw_str->type = Draw_str; + draw_str->color = color_NG; + draw_str->cp = cp; + draw_str->txtP = cv::Point(draw_qx->cp.x + r, draw_qx->cp.y - r); + draw_str->txtsize = 0.5; + draw_str->txtbackgroundk = txtbackgroundk; + cv::Rect srcroi = pqx->srcImgroi; + cv::Point srccp = cv::Point(srcroi.x + srcroi.width * .5, srcroi.y + srcroi.height * 0.5); + + char buffer[128]; + { + std::string text = std::to_string(pqx->idx) + ":" + pqx->strTypeName; + draw_str->strlist.push_back(text); + } + { + sprintf(buffer, " center:%d %d", srccp.x, srccp.y); + std::string text = buffer; + draw_str->strlist.push_back(text); + } + { + sprintf(buffer, " len %0.2f A: %0.2f ", pqx->len, pqx->area); + std::string text = buffer; + draw_str->strlist.push_back(text); + } + { + sprintf(buffer, " breadth %0.2f A: %0.2f ", pqx->breadth, pqx->area); + std::string text = buffer; + draw_str->strlist.push_back(text); + } + { + sprintf(buffer, " E:%0.2f hj %0.2f", pqx->energy, pqx->hj); + std::string text = buffer; + draw_str->strlist.push_back(text); + } + sendTask(draw_str); + // 在小图上绘制 + { + cv::Rect drawroi = pqx->CutImgroi; + cv::Point cp = cv::Point(drawroi.x + drawroi.width * .5, drawroi.y + drawroi.height * 0.5); + int r = drawroi.width; + if (drawroi.height > r) + { + r = drawroi.height; + } + r += 10; + std::shared_ptr draw_qx_small = std::make_shared(); + draw_qx_small->drawImg = pqx->srcImg; + draw_qx_small->cp = cp; + draw_qx_small->dr = r; + draw_qx_small->color = color_NG; + draw_qx_small->type = Draw_circle; + sendTask(draw_qx_small); + std::shared_ptr draw_str_small = std::make_shared(); + draw_str_small->drawImg = pqx->srcImg; + draw_str_small->type = Draw_str; + draw_str_small->color = color_NG; + draw_str_small->txtP = cp; + draw_str_small->cp = cp; + draw_str_small->strlist.assign(draw_str->strlist.begin(), draw_str->strlist.end()); + draw_str_small->txtsize = 0.45; + sendTask(draw_str_small); + } + } + for (int i = 0; i < m_CheckResult_shareP->YS_ImageResult.size(); i++) + { + std::shared_ptr draw_qx = std::make_shared(); + + QXImageResult *pqx = &m_CheckResult_shareP->YS_ImageResult.at(i); + cv::Rect drawroi = pqx->resizeImgroi; + + cv::Point cp = cv::Point(drawroi.x + drawroi.width * .5, drawroi.y + drawroi.height * 0.5); + int r = drawroi.width; + if (drawroi.height > r) + { + r = drawroi.height; + } + r += 10; + draw_qx->dr = r; + draw_qx->cp = cp; + draw_qx->color = color_Ys; + draw_qx->drawImg = m_CheckResult_shareP->resultimg; + draw_qx->type = Draw_circle; + sendTask(draw_qx); + + std::shared_ptr draw_str = std::make_shared(); + draw_str->drawImg = m_CheckResult_shareP->resultimg; + draw_str->type = Draw_str; + draw_str->color = color_Ys; + draw_str->cp = cp; + draw_str->txtP = cv::Point(draw_qx->cp.x + r, draw_qx->cp.y - r); + draw_str->txtbackgroundk = txtbackgroundk; + draw_str->txtsize = 0.5; + cv::Rect srcroi = pqx->srcImgroi; + cv::Point srccp = cv::Point(srcroi.x + srcroi.width * .5, srcroi.y + srcroi.height * 0.5); + + char buffer[128]; + { + std::string text = std::to_string(pqx->idx); + draw_str->strlist.push_back(text); + } + // { + // sprintf(buffer, " center:%d %d", srccp.x, srccp.y); + // std::string text = buffer; + // draw_str->strlist.push_back(text); + // } + // { + // sprintf(buffer, " len %0.2f A: %0.2f ", pqx->len, pqx->area); + // std::string text = buffer; + // draw_str->strlist.push_back(text); + // } + // { + // sprintf(buffer, " E:%0.2f hj %0.2f", pqx->energy, pqx->hj); + // std::string text = buffer; + // draw_str->strlist.push_back(text); + // } + sendTask(draw_str); + // 在小图上绘制 + { + cv::Rect drawroi = pqx->CutImgroi; + cv::Point cp = cv::Point(drawroi.x + drawroi.width * .5, drawroi.y + drawroi.height * 0.5); + int r = drawroi.width; + if (drawroi.height > r) + { + r = drawroi.height; + } + r += 10; + std::shared_ptr draw_qx_small = std::make_shared(); + draw_qx_small->drawImg = pqx->srcImg; + draw_qx_small->cp = cp; + draw_qx_small->dr = r; + draw_qx_small->color = color_Ys; + draw_qx_small->type = Draw_circle; + sendTask(draw_qx_small); + std::shared_ptr draw_str_small = std::make_shared(); + draw_str_small->drawImg = pqx->srcImg; + draw_str_small->type = Draw_str; + draw_str_small->color = color_Ys; + draw_str_small->txtP = cp; + draw_str_small->cp = cp; + draw_str_small->strlist.assign(draw_str->strlist.begin(), draw_str->strlist.end()); + draw_str_small->txtsize = 0.45; + sendTask(draw_str_small); + } + } + + std::shared_ptr pDetResult = pImageResult->pDetResult; // 检测结果 + + int qxNum = pDetResult->pQx_ErrorList->size(); + + for (int qxidx = 0; qxidx < qxNum; qxidx++) + { + QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx); + // 只绘制 未分析 或分析失败的。 + if (QX_info->result != QX_RESULT_TYPE_NoJduge) + { + continue; + } + + std::shared_ptr draw_qx = std::make_shared(); + + cv::Rect roi = QX_info->roi; + cv::Rect drawroi; + + drawroi.x = roi.x * fs_resize_x; + drawroi.width = roi.width * fs_resize_x; + drawroi.y = roi.y * fs_resize_y; + drawroi.height = roi.height * fs_resize_y; + + cv::Point cp = cv::Point(drawroi.x + drawroi.width * .5, drawroi.y + drawroi.height * 0.5); + int r = drawroi.width; + if (drawroi.height > r) + { + r = drawroi.height; + } + r += 10; + draw_qx->cp = cp; + draw_qx->dr = r; + draw_qx->color = color_Nojudge; + draw_qx->drawImg = m_CheckResult_shareP->resultimg; + draw_qx->type = Draw_circle; + sendTask(draw_qx); + + std::shared_ptr draw_str = std::make_shared(); + draw_str->drawImg = m_CheckResult_shareP->resultimg; + draw_str->type = Draw_str; + draw_str->color = color_Nojudge; + draw_str->cp = cp; + draw_str->txtP = cv::Point(draw_qx->cp.x + r, draw_qx->cp.y - r); + draw_str->txtbackgroundk = txtbackgroundk; + draw_str->txtsize = 0.5; + + char buffer[128]; + { + std::string text = std::to_string(QX_info->Idx); + draw_str->strlist.push_back(text); + } + sendTask(draw_str); + } + long t2 = CheckUtil::getcurTime(); + + // 等待绘制完成 + WaiteDrawComplate(); + long t3 = CheckUtil::getcurTime(); + + // printf("=====draw=all %ld send %ld wait %ld \n", t3 - t1, t2 - t1, t3 - t2); + return 0; +} + +int ImageResultJudge::GetParamidx() +{ + int region = 0; + if (m_pCommonAnalysisyConfig == NULL || m_pCommonAnalysisyConfig->regionConfigArr.size() <= 0) + { + return 1; + } + + CheckConfig_Regions_type *p = &m_pCommonAnalysisyConfig->regionConfigArr.at(region).checkConfig_Regions_type[0]; + for (int iqx = 0; iqx < CONFIG_QX_NAME_count; iqx++) + { + m_QxInParamListIdx[iqx] = -1; + std::string strqx_name = CONFIG_QX_NAME_Names[iqx]; + for (int i = 0; i < p->checkConfig_Regions_Param.size(); i++) + { + std::string strconfig_name = p->checkConfig_Regions_Param[i].param_name; + + // getchar(); + if (strqx_name == strconfig_name) + { + printf("strqx_name %s strconfig_name %s \n", strqx_name.c_str(), strconfig_name.c_str()); + m_QxInParamListIdx[iqx] = i; + break; + } + } + } + // getchar(); + return 0; +} + +int ImageResultJudge::addInDrawBlob(int errortype, int blobidx, QX_ERROR_INFO_ *QX_info, float fs_resize_x, float fs_resize_y) +{ + return 0; +} + +int ImageResultJudge::ConfigTypeToResultType(int nconfigType) +{ + + bool bdesc = false; + int resultError_type = ERROR_TYPE_OK; + if(nconfigType < CONFIG_QX_NAME_Names.size()) + { + string cqn = CONFIG_QX_NAME_Names[nconfigType]; + for(int i = 0; i < m_FlawCodeList.size(); i++) + { + for(int j = 0; j < m_FlawCodeList.at(i).config_flaw_name.size(); j++) + { + if(cqn == m_FlawCodeList.at(i).config_flaw_name[j]) + { + resultError_type = i; + bdesc = true; + break; + } + } + } + } + // 如果描述没有配置,用默认值 + if(!bdesc) + { + switch (nconfigType) + { + case CONFIG_QX_NAME_cell_aotudian: + resultError_type = ERROR_TYPE_aotudian; + break; + case CONFIG_QX_NAME_cell_other: + resultError_type = ERROR_TYPE_other; + break; + case CONFIG_QX_NAME_cell_line: + resultError_type = ERROR_TYPE_line; + break; + case CONFIG_QX_NAME_cell_zangwu: + resultError_type = ERROR_TYPE_zangwu; + break; + case CONFIG_QX_NAME_cell_edge: + resultError_type = ERROR_TYPE_edge; + break; + case CONFIG_QX_NAME_cell_ymhs: + resultError_type = ERROR_TYPE_ymhs; + break; + case CONFIG_QX_NAME_cell_dianzhuang: + resultError_type = ERROR_TYPE_dianzhuang; + break; + case CONFIG_QX_NAME_cell_posun: + resultError_type = ERROR_TYPE_posun; + break; + case CONFIG_QX_NAME_cell_xianwei: + resultError_type = ERROR_TYPE_xianwei; + break; + case CONFIG_QX_NAME_cell_shuizi: + resultError_type = ERROR_TYPE_shuizi; + break; + case CONFIG_QX_NAME_cell_danban: + resultError_type = ERROR_TYPE_danban; + break; + case CONFIG_QX_NAME_cell_fuchen: + resultError_type = ERROR_TYPE_fuchen; + break; + + default: + break; + } + } + + return resultError_type; +} + +int ImageResultJudge::sendTask(std::shared_ptr task) +{ + { + std::lock_guard lock(m_task_mutex_); + m_DrawInfoList.push(task); + } + m_task_cv_.notify_one(); + return 0; +} + +std::shared_ptr ImageResultJudge::GetTask() +{ + std::shared_ptr task; + { + std::unique_lock lock(m_task_mutex_); + m_task_cv_.wait(lock, [this]() + { return !m_DrawInfoList.empty(); }); + + task = std::move(m_DrawInfoList.front()); + m_DrawInfoList.pop(); + } + + return task; +} + +void ImageResultJudge::ThreadDraw() +{ + while (!m_bExit) + { + std::this_thread::sleep_for(std::chrono::milliseconds(0)); + // 等待是否有任务 + std::shared_ptr draw = GetTask(); + + // 把任务发送给对应的任务处理函数进行处理 + DrawResultTask(draw); + m_drawComplate_cv_.notify_all(); + } +} + +int ImageResultJudge::DrawResultTask(std::shared_ptr task) +{ + + if (task->type == Draw_circle) + { + cv::circle(task->drawImg, task->cp, task->dr, task->color); + if (task->txtbackgroundk) + { + task->txtbackgroundk->txtDrawRoi.push_back(task->roi); + } + } + if (task->type == Draw_rect) + { + cv::rectangle(task->drawImg, task->roi, task->color); + if (task->txtbackgroundk) + { + task->txtbackgroundk->txtDrawRoi.push_back(task->roi); + } + } + if (task->type == Draw_str) + { + int fontFace = cv::FONT_HERSHEY_SIMPLEX; + double fontScale = task->txtsize; + int thickness = 0.5; + int baseline = 0; + + // 行高(根据字体大小计算) + + int txtH = cv::getTextSize("Test", fontFace, fontScale, thickness, &baseline).height; + int lineHeight = txtH + 5; + // 起始位置 + int x = task->txtP.x; + int y = task->txtP.y; + + int height = 0; + int maxw = 0; + for (const auto &txt : task->strlist) + { + // 计算文本大小 + cv::Size textSize = cv::getTextSize(txt, fontFace, fontScale, thickness, &baseline); + if (textSize.width > maxw) + { + maxw = textSize.width; + } + height += lineHeight; // 下一行 + } + cv::Rect rtxt = cv::Rect(x, y - txtH, maxw, height); + cv::Rect r = cv::Rect(x, y, maxw, height); + if (task->txtbackgroundk) + { + + cv::Rect newr = task->txtbackgroundk->findNonOverlappingPos(rtxt); + task->txtbackgroundk->txtDrawRoi.push_back(newr); + rtxt = newr; + r = rtxt; + r.y += txtH; + } + + // 左边界 + if (r.x < 0) + r.x = 0; + // 上边界 + if (r.y < 0) + r.y = 0; + // 右边界 + if (r.x + r.width > task->drawImg.cols) + r.x = task->drawImg.cols - r.width; + // 下边界 + if (r.y + r.height > task->drawImg.rows) + r.y = task->drawImg.rows - r.height; + + height = 0; + for (const auto &txt : task->strlist) + { + + // 画文字 + cv::putText(task->drawImg, txt, cv::Point(r.x, r.y + height), + fontFace, fontScale, task->color, thickness); + height += lineHeight; // 下一行 + } + // cv::rectangle(task->drawImg, rtxt, cv::Scalar(255, 0, 0)); + + cv::Point p(r.x, r.y); + if (task->cp.x - r.x > 30 || task->cp.y - r.y > 30) + { + cv::line(task->drawImg, p, task->cp, cv::Scalar(80, 0, 200)); + } + + // cv::circle(task->drawImg, task->cp, 3, task->color); + } + + return 0; +} + +int ImageResultJudge::WaiteDrawComplate() +{ + { + std::unique_lock lock(m_task_mutex_); + m_drawComplate_cv_.wait(lock, [this]() + { return m_DrawInfoList.empty(); }); + } + return 0; +} diff --git a/AlgorithmModule/src/ImageStorage.cpp b/AlgorithmModule/src/ImageStorage.cpp new file mode 100644 index 0000000..d62e97c --- /dev/null +++ b/AlgorithmModule/src/ImageStorage.cpp @@ -0,0 +1,85 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-09-11 15:32:52 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-16 09:40:36 + * @FilePath: /BOE_CELL_AOI_Detect/AlgorithmModule/src/ImageStorage.cpp + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#include "ImageStorage.h" +#include +#include + +ImageStorage *ImageStorage::instance = nullptr; + +ImageStorage::ImageStorage() : stopFlag(false) +{ + // 启动存储线程 + storageThread = std::thread(&ImageStorage::storeImages, this); +} + +ImageStorage::~ImageStorage() +{ + stop(); // 在销毁时确保线程被正确停止 +} + +// 获取单例实例的静态方法 +ImageStorage *ImageStorage::getInstance() +{ + if (instance == nullptr) + { + instance = new ImageStorage(); // 如果实例为空,则创建新实例 + } + return instance; +} + +void ImageStorage::storeImages() +{ + while (!stopFlag) + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Sleep for 100 milliseconds + std::unique_lock lock(queueMutex); + cv.wait(lock, [this]() + { return !imageQueue.empty() || stopFlag; }); + + if (stopFlag && imageQueue.empty()) + break; + + auto item = imageQueue.front(); + imageQueue.pop(); + lock.unlock(); + cv::Mat temimg = item.first; + if (!temimg.empty()) + { + cv::imwrite(item.second, item.first); // 保存图片到文件 + // std::cout << "Image saved to: " << item.second << std::endl; + } + } +} + +int ImageStorage::addImage(const std::string &path, const cv::Mat &image, bool badd) +{ + std::lock_guard lock(queueMutex); + + if (imageQueue.size() > 1000 && !badd) + { + std::cout << "Queue has more than 10 items, not adding new images." << std::endl; + return 1; + } + else + { + imageQueue.push({image, path}); + cv.notify_one(); // 通知存储线程处理新任务 + } + return 0; +} + +void ImageStorage::stop() +{ + stopFlag = true; + cv.notify_one(); // 通知存储线程停止 + if (storageThread.joinable()) + { + storageThread.join(); // 等待线程退出 + } +} diff --git a/AlgorithmModule/src/ImgCheckAnalysisy.cpp b/AlgorithmModule/src/ImgCheckAnalysisy.cpp new file mode 100644 index 0000000..52eecbf --- /dev/null +++ b/AlgorithmModule/src/ImgCheckAnalysisy.cpp @@ -0,0 +1,2261 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:50:00 + * @LastEditTime: 2025-09-23 11:34:53 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/src/CamDeal.cpp + */ +#include "ImgCheckAnalysisy.hpp" +#include "CheckUtil.hpp" +#include "Define.h" +#include +#include "AICommonDefine.h" +// 用于排序轮廓的比较函数 +static bool compareContourAreas(const vector &contour1, const vector &contour2) +{ + double i = contourArea(contour1); + double j = contourArea(contour2); + return (i > j); +} +ImgCheckAnalysisy::ImgCheckAnalysisy() + : m_pAI_Edge_Algin(m_pdetlog) +{ + + m_nErrorCode = CHECK_OK; + m_nThreadIdx = -1; + m_bInitSucc = false; + m_bExit = false; + m_nRun_Status = CHECK_THREAD_STATUS_IDLE; + + m_fImgage_Scale_X = 0.03f; + m_fImgage_Scale_Y = 0.03f; + m_pBasicConfig = NULL; + + m_strCurDetChannel = ""; + m_bupdateconfig = false; + m_pbaseCheckFunction = &m_AnalysisyConfig.baseFunction; + + m_strLastDate = ""; + m_strRootPath_TA_cls = "/home/aidlux/BOE/Cls/TA/"; + m_strRootPath_CA_cls = "/home/aidlux/BOE/Cls/CA/"; + creatsavedir(); + m_pImageStorage = ImageStorage::getInstance(); + m_nConfigIdx = -1; + m_ImgBlobHFlagData = NULL; +} + +ImgCheckAnalysisy::~ImgCheckAnalysisy() +{ + ExitSystem(); + if (m_ImgBlobHFlagData) + { + delete[] m_ImgBlobHFlagData; + m_ImgBlobHFlagData = NULL; + } +} +int ImgCheckAnalysisy::UpdateConfig(void *pconfig, int nConfigType) +{ + int re = 0; + switch (nConfigType) + { + case CHECK_CONFIG_Run: + re = LoadRunConfig(pconfig); + if (re == 0) + { + // printf("---> LoadRunConfig Succ\n"); + } + else + { + printf("---> LoadRunConfig Fail\n"); + } + break; + case CHECK_CONFIG_Module: + re = LoadCheckConfig(pconfig); + if (re == 0) + { + // printf("---> LoadAnalysisConfig Succ\n"); + } + else + { + printf("---> LoadAnalysisConfig Fail\n"); + } + break; + default: + break; + } + return re; +} +int ImgCheckAnalysisy::RunStart(void *pconfig1) +{ + + // 1 、更新参数 并判断参数是否合法 + int re = CHECK_OK; + re = SetNewConfig(); + if (CHECK_OK != re) + { + m_nErrorCode = re; + return m_nErrorCode; + } + // printf("---> RunStart Start m_RunConfig.nThreadIdx %d \n", m_RunConfig.nThreadIdx); + + m_nThreadIdx = m_RunConfig.nThreadIdx; + + re = InitRun(m_RunConfig.nCpu_start_Idx); + if (CHECK_OK != re) + { + m_nErrorCode = re; + return m_nErrorCode; + } + runner = std::make_shared(); + runner->Start(); + + m_nErrorCode = CHECK_OK; + // printf("ImgCheckAnalysisy >>>> ImgCheckThread %d Start Succ \n", m_nThreadIdx); + return m_nErrorCode; +} + +int ImgCheckAnalysisy::SetDataRun_SharePtr(std::shared_ptr p) +{ + // 设置正在检测 + + m_pImageAllResult = p; + DetImgInfo_shareP = p->result->in_shareImage; + m_CheckResult_shareP = p->result; + m_pImageAllResult->setStep(ImageAllResult::DetStep_Deting); + m_pdetlog = p->detlog; + m_pDetResult = p->pDetResult; + StartCheck(); + m_nErrorCode = CHECK_OK; + return m_nErrorCode; +} + +int ImgCheckAnalysisy::GetCheckReuslt(std::shared_ptr &pResult) +{ + + m_CheckResult_shareP.reset(); + DetImgInfo_shareP.reset(); + SetIDLE(); + // m_nErrorCode = CHECK_OK; + // printf("4 DetImgInfo_shareP count %ld m_nCheckResultErrorCode %d \n", DetImgInfo_shareP.use_count(), m_nCheckResultErrorCode); + return m_nCheckResultErrorCode; +} + +int ImgCheckAnalysisy::CheckImg(std::shared_ptr p, std::shared_ptr &pResult) +{ + + return 0; +} + +int ImgCheckAnalysisy::ReJsonResul(std::shared_ptr p, std::shared_ptr &pResult) +{ + + return 0; +} + +int ImgCheckAnalysisy::InitRun(int nId) +{ + + int re = CHECK_OK; + if (m_bInitSucc) + { + return CHECK_OK; + } + InitModel(); + AI_Factory = AIFactory::GetInstance(); + + m_nRun_Status = CHECK_THREAD_STATUS_IDLE; + re = StartThread(nId); + if (CHECK_OK != re) + { + return re; + } + m_bInitSucc = true; + return re; +} + +int ImgCheckAnalysisy::GetStatus() +{ + return m_nRun_Status; +} + +std::string ImgCheckAnalysisy::GetVersion() +{ + return std::string("BOE_1.7.91"); +} + +std::string ImgCheckAnalysisy::GetErrorInfo() +{ + std::string str = GetErrorCodeInfo(m_nErrorCode); + printf("%s\n", str.c_str()); + return str; +} + +int ImgCheckAnalysisy::creatsavedir() +{ + std::string curDate = CheckUtil::getCurrentDate(); + if (curDate == m_strLastDate) + { + return 0; + } + m_strLastDate = curDate; + m_strRootPath_TA_cls += m_strLastDate + "/"; + m_strRootPath_CA_cls += m_strLastDate + "/"; + for (int i = 0; i < AI_CLass_QX_NAME_count; i++) + { + CheckUtil::CreateDir(m_strRootPath_TA_cls + std::to_string(i) + "/"); + CheckUtil::CreateDir(m_strRootPath_CA_cls + std::to_string(i) + "/"); + } + return 0; +} + +int ImgCheckAnalysisy::LoadRunConfig(void *p) +{ + if (p == NULL) + { + m_nErrorCode = CHECK_ERROR_Config_Null; + return m_nErrorCode; + } + RunInfoST *pconfig = (RunInfoST *)p; + m_RunConfig.copy(*pconfig); + + return CHECK_OK; +} + +int ImgCheckAnalysisy::LoadCheckConfig(void *p) +{ + if (p == NULL) + { + m_nErrorCode = CHECK_ERROR_Config_Null; + return m_nErrorCode; + } + m_pConfig = (ConfigBase *)p; + m_nConfigIdx = m_pConfig->GetConfigIdx(); + m_nErrorCode = CHECK_OK; + return m_nErrorCode; +} + +// 开启检测 +int ImgCheckAnalysisy::StartCheck() +{ + m_nRun_Status = CHECK_THREAD_STATUS_READY; + return 0; +} + +int ImgCheckAnalysisy::SetIDLE() +{ + // 更新参数 + SetNewConfig(); + m_nRun_Status = CHECK_THREAD_STATUS_IDLE; + return 0; +} + +int ImgCheckAnalysisy::StartThread(int nId) +{ + // 开启检测线程 + ptr_thread_Run = std::make_shared(std::bind(&ImgCheckAnalysisy::Run, this, nId)); + if (!m_RunConfig.bRetest) + { + ptr_thread_AI = std::make_shared(std::bind(&ImgCheckAnalysisy::ThreadTask, this, nId + 1)); + } + + return 0; +} + +int ImgCheckAnalysisy::StopThread() +{ + m_bExit = true; + if (ptr_thread_Run != nullptr) + { + if (ptr_thread_Run->joinable()) + { + ptr_thread_Run->join(); + } + } + if (ptr_thread_AI != nullptr) + { + if (ptr_thread_AI->joinable()) + { + ptr_thread_AI->join(); + } + } + return 0; +} + +int ImgCheckAnalysisy::ExitSystem() +{ + StopThread(); + return 0; +} + +int ImgCheckAnalysisy::InitModel() +{ + + // 获取当前gpu号确定的 AI处理线程 + + m_OtherDet_Config.nDeviceId = m_RunConfig.nDeviceId; + + m_pAI_Edge_Algin.Init(&m_OtherDet_Config); + m_pAI_Edge_Algin.InitModel_ALL(); + + return 0; +} + +cv::Scalar ImgCheckAnalysisy::calc_blob_info_withstats(cv::Mat &img, const cv::Mat &mask, cv::Rect &stats, cv::Size k_size, int expand, double threshold) +{ + + // 解包 stats(x, y, w, h, area) + int x = stats.x, y = stats.y, w = stats.width, h = stats.height; + + // 将图像转换为灰度图像 + + // 计算感兴趣区域 (ROI) + cv::Rect roi(x - expand, y - expand, w + 2 * expand, h + 2 * expand); + roi &= cv::Rect(0, 0, img.cols, img.rows); // 确保ROI在图像内 + + cv::Mat cimg = img(roi); + + // cv::cvtColor(cimg, cimg, cv::COLOR_BGR2GRAY); + // return cv::Scalar(0, 0, 0); + + cv::Mat cmask = mask(roi); + // getchar(); + // 扩张掩膜 + + cv::Scalar mean_bk = cv::mean(cimg, ~cmask); + double fbk = mean_bk[0]; + + cv::Scalar mean_det = cv::mean(cimg, cmask); + double fdet = mean_det[0]; + + // 计算差异图像 + cv::Mat diff = cv::abs(cimg - fbk); + + // cv::imwrite("cimg.png",cimg); + // cv::imwrite("cmask.png",cmask); + // printf("%f %f - %f \n",fbk,fdet,fbk-fdet); + // getchar(); + + // diff = diff.mul(cmask > 0); + cv::Mat masked_image; + diff.copyTo(masked_image, cmask); + // 计算能量 + double energy = cv::sum(masked_image)[0]; + + // 计算 hj(差异图像大于0的像素均值) + // double hj = std::abs(fbk - fdet); + // double hj = CheckUtil::CalHj(cimg, cmask, mean_bk.val[0]); + double hj = CheckUtil::CalHjWeighted(cimg, cmask, mean_bk.val[0], 2.0f); + + int worb = 0; + if (fdet >= fbk) + { + worb = 1; + } + // cv::imwrite("cimg.png", cimg); + // cv::imwrite("cmask.png", cmask); + // cv::imwrite("diff.png", diff); + // cv::imwrite("masked_image.png", masked_image); + // printf("fbk %f fdet %f energy %f\n", fbk, fdet, energy); + // getchar(); + + return cv::Scalar(worb, energy, hj); +} + +Point2f GetCoorPoint(Point2f point, Mat img_mat) +{ + // 越界判定 + int coor_img_rect_x = point.x-400; + int coor_img_rect_y = point.y-400; + int coor_img_rect_w = 800; + int coor_img_rect_h = 800; + if (coor_img_rect_x < 0) + { + coor_img_rect_x = 0; + coor_img_rect_w = min(400, img_mat.cols); + } + if (coor_img_rect_y < 0) + { + coor_img_rect_y = 0; + coor_img_rect_h = min(400, img_mat.rows); + } + if (coor_img_rect_x + coor_img_rect_w > img_mat.cols) + { + coor_img_rect_w = img_mat.cols - coor_img_rect_x; + } + if (coor_img_rect_y + coor_img_rect_h > img_mat.rows) + { + coor_img_rect_h = img_mat.rows - coor_img_rect_y; + } + if (coor_img_rect_x < 0 || coor_img_rect_y < 0 || coor_img_rect_x + coor_img_rect_w > img_mat.cols || coor_img_rect_y + coor_img_rect_h > img_mat.rows) + { + return point; + } + + Mat coor_img_mat = img_mat(Rect(coor_img_rect_x, coor_img_rect_y, coor_img_rect_w, coor_img_rect_h)); + Mat coor_img_bin; + threshold(coor_img_mat, coor_img_bin, 50, 255, THRESH_BINARY); + + // 6. 查找轮廓 + std::vector> contours; + cv::findContours(coor_img_bin, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); + if (contours.empty()) + { + return point; + } + double maxArea = 0; + int maxAreaIdx = -1; + for (size_t i = 0; i < contours.size(); ++i) + { + double area = cv::contourArea(contours[i]); + if (area > maxArea) + { + maxArea = area; + maxAreaIdx = i; + } + } + if (maxAreaIdx < 0 || maxArea < 100) + { + return point; + } + cv::RotatedRect rect = cv::minAreaRect(contours[maxAreaIdx]); + Point2f vertices[4]; + rect.points(vertices); + + int cornerIdx = 0; + float minDist = FLT_MAX; + for (int i = 0; i < 4; i++) + { + float dist = std::pow(vertices[i].x - 400, 2) + std::pow(vertices[i].y - 400, 2); + if (dist < minDist) + { + minDist = dist; + cornerIdx = i; + } + } + + Point2f new_point; + new_point.x = vertices[cornerIdx].x + coor_img_rect_x; + new_point.y = vertices[cornerIdx].y + coor_img_rect_y; + + new_point.x = std::max(0.0f, std::min(new_point.x, static_cast(img_mat.cols - 1))); + new_point.y = std::max(0.0f, std::min(new_point.y, static_cast(img_mat.rows - 1))); + + return new_point; +} + +int GetEdgeRoi(Mat img, Rect &new_roi, float scale_x, float scale_y){ + if (img.empty()) + { + return 1; + } + // 缩小,减少耗时 + Mat r_img; + + int resize_width = static_cast(img.cols / scale_x); + int resize_height = static_cast(img.rows / scale_y); + resize(img, r_img, Size(resize_width, resize_height), 0, 0, INTER_LINEAR); + + // 二值化找最大连通域 + Mat r_img_bin; + threshold(r_img, r_img_bin, 15, 255, THRESH_BINARY); + std::vector> contours; + cv::findContours(r_img_bin, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); + if (contours.empty()) + { + return 2; + } + double maxArea = 0; + int maxAreaIdx = -1; + for (size_t i = 0; i < contours.size(); ++i) + { + double area = cv::contourArea(contours[i]); + if (area > maxArea) + { + maxArea = area; + maxAreaIdx = i; + } + } + + if (maxAreaIdx < 0) + { + return 3; + } + + cv::Rect small_roi = cv::boundingRect(contours[maxAreaIdx]); + Rect roi; + roi.x = static_cast(small_roi.x * scale_x); + roi.y = static_cast(small_roi.y * scale_y); + roi.width = static_cast(small_roi.width * scale_x); + roi.height = static_cast(small_roi.height * scale_y); + roi.x = std::max(0, roi.x); + roi.y = std::max(0, roi.y); + roi.width = std::min(roi.width, img.cols - roi.x); + roi.height = std::min(roi.height, img.rows - roi.y); + + new_roi = roi; + + return 0; +} + +int ImgCheckAnalysisy::Adapt_Config(Mat img, Rect cur_roi, bool b_update){ + if (img.empty()) { + std::cerr << "Error: Input image 'img' is empty!" << std::endl; + return -1; + } + if(!b_update){ + return 1; + } + int get_edge_roi = GetEdgeRoi(img, cur_roi, 20, 20); + if(get_edge_roi != 0){ + return 2; + } + m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "-------------------start--------------"); + + /*计算xy偏移,缩放比例*/ + // 拷贝原始数据 + if(m_old_productROI.width == 0 || m_old_productROI.height == 0){ + m_old_productROI = m_AnalysisyConfig.baseFunction.markLine.productROI; + m_old_cur_edgeDet_region = m_AnalysisyConfig.baseFunction.edgeDet.region; + m_old_cur_markLine_region = m_AnalysisyConfig.baseFunction.markLine.region; + m_old_cur_markLine_mark1 = m_AnalysisyConfig.baseFunction.markLine.mark_local_1; + m_old_cur_markLine_mark2 = m_AnalysisyConfig.baseFunction.markLine.mark_local_2; + m_old_cur_regionConfigArr = m_AnalysisyConfig.commonCheckConfig.nodeConfigArr[0].regionConfigArr; + } + Rect old_roi = m_old_productROI; + Point old_center(old_roi.x + old_roi.width / 2, old_roi.y + old_roi.height / 2); + Point new_center(cur_roi.x + cur_roi.width / 2, cur_roi.y + cur_roi.height / 2); + + int x_offset = new_center.x - old_center.x; + int y_offset = new_center.y - old_center.y; + float scale_x = (float)cur_roi.width / (float)old_roi.width; + float scale_y = (float)cur_roi.height / (float)old_roi.height; + + m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "old_roi = %d %d %d %d", old_roi.x, old_roi.y, old_roi.width, old_roi.height); + m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "cur_roi = %d %d %d %d", cur_roi.x, cur_roi.y, cur_roi.width, cur_roi.height); + m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "x_offset = %d y_offset = %d", x_offset, y_offset); + m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "scale_x = %f scale_y = %f", scale_x, scale_y); + + if(abs(x_offset) < 50 && abs(y_offset) < 50 && abs(scale_x - 1) < 0.0001 && abs(scale_y - 1) < 0.0001 ){ + return 3; + } + + /*获取待修改的region引用*/ + std::vector& cur_edgeDet_region = m_AnalysisyConfig.baseFunction.edgeDet.region; + std::vector& cur_markLine_region = m_AnalysisyConfig.baseFunction.markLine.region; + cv::Point& cur_markLine_mark1 = m_AnalysisyConfig.baseFunction.markLine.mark_local_1; + cv::Point& cur_markLine_mark2 = m_AnalysisyConfig.baseFunction.markLine.mark_local_2; + std::vector& cur_regionConfigArr = m_AnalysisyConfig.commonCheckConfig.nodeConfigArr[0].regionConfigArr; + + /*进行修改*/ + // rect + m_AnalysisyConfig.baseFunction.markLine.productROI = cur_roi; + // point + cur_markLine_mark1.x = m_old_cur_markLine_mark1.x + x_offset; + cur_markLine_mark1.y = m_old_cur_markLine_mark1.y + y_offset; + cur_markLine_mark1 = Point((cur_markLine_mark1.x - new_center.x) * scale_x + new_center.x, (cur_markLine_mark1.y - new_center.y) * scale_y + new_center.y); + cur_markLine_mark2.x = m_old_cur_markLine_mark2.x + x_offset; + cur_markLine_mark2.y = m_old_cur_markLine_mark2.y + y_offset; + cur_markLine_mark2 = Point((cur_markLine_mark2.x - new_center.x) * scale_x + new_center.x, (cur_markLine_mark2.y - new_center.y) * scale_y + new_center.y); + // region + for(int i = 0; i < cur_edgeDet_region.size(); i++){ + cur_edgeDet_region[i].x = m_old_cur_edgeDet_region[i].x + x_offset; + cur_edgeDet_region[i].y = m_old_cur_edgeDet_region[i].y + y_offset; + cur_edgeDet_region[i] = Point((cur_edgeDet_region[i].x - new_center.x) * scale_x + new_center.x, (cur_edgeDet_region[i].y - new_center.y) * scale_y + new_center.y); + } + for(int i = 0; i < cur_markLine_region.size(); i++){ + cur_markLine_region[i].x = m_old_cur_markLine_region[i].x + x_offset; + cur_markLine_region[i].y = m_old_cur_markLine_region[i].y + y_offset; + cur_markLine_region[i] = Point((cur_markLine_region[i].x - new_center.x) * scale_x + new_center.x, (cur_markLine_region[i].y - new_center.y) * scale_y + new_center.y); + } + for(int i = 0 ; i < cur_regionConfigArr.size(); i++){ + for(int j = 0; j < cur_regionConfigArr[i].basicInfo.pointArry.size(); j++){ + cur_regionConfigArr[i].basicInfo.pointArry[j].x = m_old_cur_regionConfigArr[i].basicInfo.pointArry[j].x + x_offset; + cur_regionConfigArr[i].basicInfo.pointArry[j].y = m_old_cur_regionConfigArr[i].basicInfo.pointArry[j].y + y_offset; + cur_regionConfigArr[i].basicInfo.pointArry[j] = Point((cur_regionConfigArr[i].basicInfo.pointArry[j].x - new_center.x) * scale_x + new_center.x, (cur_regionConfigArr[i].basicInfo.pointArry[j].y - new_center.y) * scale_y + new_center.y); + } + } + + /*show*/ + // Mat show_img = img.clone(); + // cv::rectangle(show_img, m_AnalysisyConfig.baseFunction.markLine.productROI, Scalar(255), 5); + // if(cur_edgeDet_region.size() >=2){ + // for(int i = 0 ; i < cur_edgeDet_region.size() - 1; i++){ + // cv::line(show_img, cur_edgeDet_region[i], cur_edgeDet_region[i+1], Scalar(255), 20); + // } + // } + // if(cur_markLine_region.size() >=2){ + // for(int i = 0 ; i < cur_markLine_region.size() - 1; i++){ + // cv::line(show_img, cur_markLine_region[i], cur_markLine_region[i+1], Scalar(255), 20); + // } + // } + // if(cur_regionConfigArr.size() >=2){ + // for(int i = 0 ; i < cur_regionConfigArr.size(); i++){ + // for(int j = 0; j < cur_regionConfigArr[i].basicInfo.pointArry.size()-1; j++){ + // cv::line(show_img, cur_regionConfigArr[i].basicInfo.pointArry[j], cur_regionConfigArr[i].basicInfo.pointArry[j+1], Scalar(255), 20); + // } + // } + // } + // imwrite(m_AnalysisyConfig.commonCheckConfig.baseConfig.strCamearName +"_show_img.tiff", show_img); + + return 0; +} + +int ImgCheckAnalysisy::CheckRun() +{ + + // printf(">>>%s ================start \n", m_pImageAllResult->strBaseInfo.c_str()); + + long t1, t2, t3, t4, t5, t6, t7; + SetNewConfig(); + t1 = CheckUtil::getcurTime(); + + CheckImgInit(); + if (DetImgInfo_shareP->bsaveProcessImg) + { + m_pdetlog->bPrintStr = true; + } + m_pdetlog->bPrintStr = true; + + m_pdetlog->AddCheckstr(PrintLevel_0, "1、basic Info", "---------------------------1、basic Info---------------------------------"); + m_pdetlog->AddCheckstr(PrintLevel_0, "Version", "%s", GetVersion().c_str()); + m_pdetlog->AddCheckstr(PrintLevel_0, "Updateconfig", "%d", m_bupdateconfig); + m_pdetlog->AddCheckstr(PrintLevel_0, "Start", "%s", m_pImageAllResult->strBaseInfo.c_str()); + m_pdetlog->AddCheckstr(PrintLevel_0, "ImgageScale", "Scale_X = %f Scale_Y = %f", m_fImgage_Scale_X, m_fImgage_Scale_Y); + m_bupdateconfig = false; + // 返回结果状态初始化 + m_CheckResult_shareP->checkStatus = 1; + m_CheckResult_shareP->nresult = -1; + + m_CheckResult_shareP->basicResult.img_id = m_CheckResult_shareP->in_shareImage->img_id; + m_CheckResult_shareP->basicResult.imgtype = m_CheckResult_shareP->in_shareImage->imgtype; + m_CheckResult_shareP->basicResult.imgstr = m_CheckResult_shareP->in_shareImage->imgstr; + m_CheckResult_shareP->basicResult.strChannel = m_CheckResult_shareP->in_shareImage->strChannel; + m_strCurDetChannel = m_CheckResult_shareP->basicResult.strChannel; + + /*自适应更新参数*/ + // int64 t000 = cv::getTickCount(); + // m_pdetlog->bPrintStr = true; + Adapt_Config(m_CheckResult_shareP->in_shareImage->img, m_CutRoi, m_pbaseCheckFunction->markLine.badapt_region); + // m_pdetlog->bPrintStr = false; + // int64 t111 = cv::getTickCount(); + // cout << "-------------------------Adapt_Config------------succ---time ----" << (t111 - t000) * 1000 / cv::getTickFrequency() << "ms" << endl; + + // 2、参数检查 + int rec = ConfigCheck(DetImgInfo_shareP->img); + if (rec != CHECK_OK) + { + m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "ConfigCheck is error type = %d", rec); + m_nErrorCode = rec; + m_nCheckResultErrorCode = m_nErrorCode; + return m_nErrorCode; + } + long time_edge_s = CheckUtil::getcurTime(); + // 3、AI 边缘定位 + int reedge = AI_Edge(m_CheckResult_shareP->in_shareImage->img, m_CutRoi); + if (reedge != 0) + { + m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "AI_Edge is error type = %d", reedge); + m_nErrorCode = reedge; + m_nCheckResultErrorCode = m_nErrorCode; + return m_nErrorCode; + } + long time_edge_e = CheckUtil::getcurTime(); + m_pdetlog->AddCheckstr(PrintLevel_0, "2、pre detect", "-------------------------AI_Edge------------succ---time %ld----\n", time_edge_e - time_edge_s); + + m_Crop_Roi_paramImg = m_CutRoi; + m_pImageAllResult->pDetResult->CutRoi = m_CutRoi; + m_pImageAllResult->pDetResult->Param_CropRoi = m_Crop_Roi_paramImg; + + // 生成 检测的图片 + cv::Mat image; + image = m_CheckResult_shareP->in_shareImage->img; + if (image.channels() == 3) + { + cv::cvtColor(image(m_CutRoi), m_pImageAllResult->detImg, cv::COLOR_RGB2GRAY); + } + else + { + m_pImageAllResult->detImg = image(m_CutRoi).clone(); + } + // 多线程开启 AI 推理检测 + long time_AI_s = CheckUtil::getcurTime(); + m_AItask = std::make_shared(); + m_AItask->taskname = Task_AI; + m_task.sendTask(m_AItask); + + ImgPreDet(); + // 更新检测区域 + Update_DetRoiList(); + + m_pdetlog->AddCheckstr(PrintLevel_0, "3、pre detect", "-------------------------pre Det--------------- \n"); + + // 实现边缘崩溃缺陷检测 + { + long t41 = CheckUtil::getcurTime(); + int reedge1111 = Edge_Qx_Det(m_pImageAllResult->detImg); + long t42 = CheckUtil::getcurTime(); + m_pdetlog->AddCheckstr(PrintLevel_0, "4、detect", "-------------------------1、Edge_Qx_Det--------%ld-------\n", t42 - t41); + } + + m_CheckResult_shareP->nresult = 0; + + // 把临时可以绘制的结果都绘制出来。 + DrawResult_Step_1(); + long time_AI_e; + // AI 推理生成 + { + long t211 = CheckUtil::getcurTime(); + // 对AI的结果进行 处理,等待 AI 推理全部完成。 + rec = AIMaskDet(); + if (rec != CHECK_OK) + { + m_nErrorCode = rec; + m_nCheckResultErrorCode = m_nErrorCode; + return m_nErrorCode; + } + time_AI_e = CheckUtil::getcurTime(); + m_pdetlog->AddCheckstr(PrintLevel_0, "4、detect", "-------------------------2、AI Detect--------%ld wait AI complate %ld-------\n", time_AI_e - time_AI_s, time_AI_e - t211); + + m_CheckResult_shareP->resultMaskImg = m_pImageAllResult->AIMaskImg; + } + + { + + t4 = CheckUtil::getcurTime(); + rec = GetCheckResultBLob(); + if (rec != CHECK_OK) + { + m_nErrorCode = rec; + m_nCheckResultErrorCode = m_nErrorCode; + return m_nErrorCode; + } + t5 = CheckUtil::getcurTime(); + m_pdetlog->AddCheckstr(PrintLevel_0, "5、BLob ", "------------------------ --------%ld -------\n", t5 - t4); + } + // m_pdetlog->printLog(m_strCurDetChannel); + + long te = CheckUtil::getcurTime(); + m_pdetlog->bPrintStr = true; + m_pdetlog->AddCheckstr(PrintLevel_1, "result", " ALL use Time %ld edge %ld AI %ld blob %ld", + te - t1, time_edge_e - time_edge_s, time_AI_e - time_AI_s, t5 - t4); + + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, "End", " Check Run"); + + return 0; +} + +int ImgCheckAnalysisy::SetNewConfig() +{ + if (m_nConfigIdx < 0) + { + return 1; + /* code */ + } + + if (m_pConfig->GetConfigUpdataStatus(ConfigType_Analysisy_Common_XL, m_nConfigIdx)) + { + m_bupdateconfig = true; + // printf("************** ImgCheckAnalysisy::SetNewConfig m_nConfigIdx %d\n", m_nConfigIdx); + m_old_productROI = cv::Rect(0, 0, 0, 0); + m_pConfig->GetConfig(ConfigType_Analysisy_Common_XL, &m_AnalysisyConfig); + if (m_AnalysisyConfig.commonCheckConfig.nodeConfigArr.size() > 0) + { + m_pCommonAnalysisyConfig = &m_AnalysisyConfig.commonCheckConfig.nodeConfigArr.at(0); + m_pBasicConfig = &m_AnalysisyConfig.commonCheckConfig.baseConfig; + m_pRegionAnalysisyParam = &m_pCommonAnalysisyConfig->regionConfigArr.at(0); + + UpdateImgageScale(); + if (false) + { + printf("SetNewConfig m_nConfigIdx %d m_CheckConfig.strSkuName %s \n", m_nConfigIdx, m_AnalysisyConfig.strSkuName.c_str()); + } + } + else + { + printf("m_AnalysisyConfig.commonCheckConfig.nodeConfigArr == 0 \n"); + } + } + else + { + // printf("ConfigType_Analysisy_Common_XL no Update \n"); + } + m_nErrorCode = CHECK_OK; + return CHECK_OK; +} + +ChannelCheckFunction *ImgCheckAnalysisy::GetChannelFuntion(std::string strChannelName) +{ + ChannelCheckFunction *p = NULL; + for (int i = 0; i < m_AnalysisyConfig.checkFunction.channelFunctionArr.size(); i++) + { + if (CheckUtil::compareIgnoreCase(m_AnalysisyConfig.checkFunction.channelFunctionArr[i].strChannelName, strChannelName)) + { + p = &m_AnalysisyConfig.checkFunction.channelFunctionArr[i]; + } + } + + return p; +} +int ImgCheckAnalysisy::Run(int nId) +{ + std::vector vi; + vi.push_back(nId); + auto nRet = set_cpu_id(vi); + // printf("Check So %d bind cpu ret %d, %d\n", m_nThreadIdx, nRet, nId); + while (!m_bExit) + { + // 数据准备完成,开启检测 + if (m_nRun_Status == CHECK_THREAD_STATUS_READY) + { + m_nRun_Status = CHECK_THREAD_STATUS_BUSY; + /* 检测 */ + CheckRun(); + m_nRun_Status = CHECK_THREAD_STATUS_COMPLETE; + m_pImageAllResult->setStep(ImageAllResult::DetStep_Complet); + m_nRun_Status = CHECK_THREAD_STATUS_IDLE; + // printf("*--------%d\n", m_nRun_Status); + } + else + { + + usleep(1000); + } + // printf("*-"); + usleep(1000); + } + return 0; +} +int ImgCheckAnalysisy::set_cpu_id(const std::vector &cpu_set_vec) +{ + // for cpu affinity + int nRet = 0; +#ifdef __linux + cpu_set_t _cur_cpu_set; + CPU_ZERO(&_cur_cpu_set); + for (auto _id : cpu_set_vec) + { + CPU_SET(_id, &_cur_cpu_set); + } + if (0 > pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &_cur_cpu_set)) + { + perror("set cpu affinity failed: "); + printf("Warning: set cpu affinity failed ... ...\n"); + nRet = -1; + } +#endif //__linux + return nRet; +} + +int ImgCheckAnalysisy::CalBlob_Other() +{ + + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "CalBlob_Other", " Start"); + + float fs_x = m_fImgage_Scale_X; + float fs_y = m_fImgage_Scale_Y; + + float fs_resize_x = m_pImageAllResult->fscale_detToresult_x; + float fs_resize_y = m_pImageAllResult->fscale_detToresult_y; + // 遍历每个检测blob + for (int i = 0; i < blobs.blobCount; i++) + { + + // m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Blob", "%d/%d start", i, blobs.blobCount); + + cv::Rect roi; + roi.x = blobs.blobTab[i].minx; + roi.y = blobs.blobTab[i].miny; + roi.width = blobs.blobTab[i].maxx - blobs.blobTab[i].minx + 1; + roi.height = blobs.blobTab[i].maxy - blobs.blobTab[i].miny + 1; + + cv::Scalar result = calc_blob_info_withstats(m_pImageAllResult->detImg, m_pImageAllResult->AIMaskImg, roi); + + int QX_whiteBLACK = CONFIG_QX_BLACK; + if (result[0] > 0) + { + QX_whiteBLACK = CONFIG_QX_WHITE; + } + + double hj = result[2]; + double energe = result[1]; + blobs.blobTab[i].energy = energe; + blobs.blobTab[i].grayDis = hj; + + float JudgArea = blobs.blobTab[i].area * fs_x * fs_y; + blobs.blobTab[i].JudgArea = JudgArea; + float flen = roi.width * fs_x; + float fwid = roi.height * fs_x; + if (roi.height * fs_y > flen) + { + flen = roi.height * fs_y; + fwid = roi.width * fs_y; + } + blobs.blobTab[i].len = flen; + blobs.blobTab[i].breadth = fwid; + + int nerrortype = 0; + int checkFlage = 0; + + float fmaxScore = 0; + int config_qx_type = 0; + + if (blobs.blobTab[i].ErrType == ERR_TYPE_2) + { + QX_whiteBLACK = CONFIG_QX_BLACK; // 强制为 黑色 + } + blobs.blobTab[i].whiteOrblack = QX_whiteBLACK; + + // 精确计算长度 + vector re_len = Cal_QXLen(m_pImageAllResult->detImg(roi), config_qx_type, fs_x, fs_y); + + if (re_len.size() > 2) + { + if(re_len[0] >= 0){ + flen = re_len[0]; + blobs.blobTab[i].len = flen; + } + if(re_len[1] >= 0){ + fwid = re_len[1]; + blobs.blobTab[i].breadth = fwid; + } + + } + } + return 0; +} + +int ImgCheckAnalysisy::GetClassImg(const cv::Mat &img, cv::Mat &AIdetImg, cv::Rect qx_roi, int detwidth, int detheight) +{ + + cv::Rect cutroi; + cv::Rect roi = qx_roi; + bool bresize = false; + { + + int pc_x = roi.x + roi.width * 0.5; + int pc_y = roi.y + roi.height * 0.5; + + if (roi.width < detwidth && roi.height < detheight) + { + cutroi.width = detwidth; + cutroi.x = pc_x - detwidth * 0.5; + cutroi.height = detheight; + cutroi.y = pc_y - detheight * 0.5; + } + else + { + // 宽 高 + if (roi.width > roi.height) + { + cutroi.width = roi.width + 20; + cutroi.x = roi.x - 10; + + float fsx = detheight * 1.0f / detwidth; + cutroi.height = cutroi.width * fsx; + cutroi.y = pc_y - cutroi.height * 0.5; + } + else + { + cutroi.height = roi.height + 20; + cutroi.y = roi.y - 10; + + float fsy = detwidth * 1.0f / detheight; + cutroi.width = cutroi.height * fsy; + cutroi.x = pc_x - cutroi.width * 0.5; + } + + bresize = true; + } + + if (cutroi.x < 0) + { + cutroi.x = 0; + } + if (cutroi.y < 0) + { + cutroi.y = 0; + } + if (cutroi.x + cutroi.width >= img.cols) + { + cutroi.x = img.cols - cutroi.width; + if (cutroi.x < 0) + { + cutroi.x = 0; + if (cutroi.x + cutroi.width >= img.cols) + { + cutroi.width = img.cols; + } + } + } + if (cutroi.y + cutroi.height >= img.rows) + { + cutroi.y = img.rows - cutroi.height; + if (cutroi.y < 0) + { + cutroi.y = 0; + if (cutroi.y + cutroi.height >= img.rows) + { + cutroi.height = img.rows; + } + } + } + } + if (!CheckUtil::RoiInImg(cutroi, img)) + { + return 1; + } + cv::Size sz; + sz.width = detwidth; + sz.height = detheight; + if (cutroi.width != sz.width || cutroi.height != sz.height) + { + cv::resize(img(cutroi), AIdetImg, sz); + } + else + { + AIdetImg = img(cutroi).clone(); + } + + if (1 != AIdetImg.channels()) + { + cv::cvtColor(AIdetImg, AIdetImg, cv::COLOR_BGR2GRAY); + } + return 0; +} + +vector ImgCheckAnalysisy::Cal_QXLen(cv::Mat qx_maskImg, int qx_type, float fsc_x, float fsc_y) +{ + vector resLen(3); + + float nlen = -1; + cv::Mat detimg = qx_maskImg; + + resLen[0] = nlen; + // 寻找轮廓 + vector> contours; + cv::findContours(detimg, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); + + // 找到最大面积的轮廓 + double maxArea = -1; + int maxAreaIdx = -1; + for (size_t i = 0; i < contours.size(); ++i) + { + double area = contourArea(contours[i]); + if (area > maxArea) + { + maxArea = area; + maxAreaIdx = i; + } + } + + // 如果找到了最大面积的轮廓 + if (maxAreaIdx >= 0) + { + + // 使用minAreaRect找到最小外接矩形 + cv::RotatedRect rect = cv::minAreaRect(contours[maxAreaIdx]); + + // // 绘制最小外接矩形 + // Point2f vertices[4]; + // rect.points(vertices); + // for (int i = 0; i < 4; ++i) + // { + // line(detimg, vertices[i], vertices[(i + 1) % 4], Scalar(128, 255, 0), 2); // 绿色线 + // } + // 输出结果 + + // 获取最小外接矩形的尺寸 + float width = rect.size.width; + float height = rect.size.height; + + // std::cout << "1 Width: " << width << ", Height: " << height << std::endl; + Point2f vertices[4]; + rect.points(vertices); + + vector newcont; + for (int i = 0; i < 4; ++i) + { + Point2f p; + p.x = vertices[i].x * fsc_x; + p.y = vertices[i].y * fsc_y; + newcont.push_back(p); + } + vector> contours_New; + contours_New.push_back(newcont); + // Recreate the rotated rectangle with scaled vertices + RotatedRect scaledRect = minAreaRect(contours_New[0]); + + // Calculate scaled width and height + width = scaledRect.size.width; + height = scaledRect.size.height; + // std::cout << "2 width: " << width << ", height: " << height << std::endl; + // float scale = 0.5; // 缩放比例 + // rect.size.width *= fsc_x; + // rect.size.height *= fsc_y; + // std::cout << "fsc_x: " << fsc_x << ", fsc_y: " << fsc_y << std::endl; + // std::cout << "Width: " << width << ", Height: " << height << std::endl; + // 获取最小外接矩形的尺寸 + // width = rect.size.width; + // height = rect.size.height; + if (width > height) + { + nlen = width; + resLen[0] = width; + resLen[1] = height; + /* code */ + } + else + { + nlen = height; + resLen[0] = height; + resLen[1] = width; + } + } + + // getchar(); + return resLen; +} + +int ImgCheckAnalysisy::GetCheckResultBLob() +{ + long t1, t2, t3, t4, t5, t6, t7; + t1 = CheckUtil::getcurTime(); + int re = GetALLBlob(); + if (re != 0) + { + return re; + } + + // 缺陷分类 多线程 实现。 + long t11 = CheckUtil::getcurTime(); + m_Classtask = std::make_shared(); + m_Classtask->taskname = Task_Class; + m_task.sendTask(m_Classtask); + + re = CalBlob_Other(); + if (re != 0) + { + return re; + } + long t12 = CheckUtil::getcurTime(); + // 等待分类 完成。 + m_Classtask->waitComplate(); + long t13 = CheckUtil::getcurTime(); + // printf("=========== cls time %ld waite time %ld\n", t13 - t11, t13 - t12); + + BLobToDetResult(); + + return 0; +} + +void worker(const unsigned char *img, int w, int startRow, int endRow, unsigned char *rowFlags) +{ + for (int y = startRow; y < endRow; y++) + { + const unsigned char *p = img + (size_t)y * w; + rowFlags[y] = 0; + for (int x = 0; x < w; x++) + { + if (p[x] != 0) + { + rowFlags[y] = 1; + break; + } + } + } +} +int ImgCheckAnalysisy::GetALLBlob() +{ + + std::string strBaseLog = "Blob"; + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "image Blob Analysis Start"); + if (m_pImageAllResult->AIMaskImg.empty()) + { + return 1; + } + unsigned char *pGrayErrordata = (unsigned char *)m_pImageAllResult->AIMaskImg.data; + int width = m_pImageAllResult->AIMaskImg.cols; + int height = m_pImageAllResult->AIMaskImg.rows; + + long t1 = CheckUtil::getcurTime(); + + memset(&blobs, 0x00, sizeof(ERROR_DOTS_BLOBS)); + + ERROR_DOTS_BLOBS blobs_v1; + memset(&blobs_v1, 0x00, sizeof(ERROR_DOTS_BLOBS)); + ERROR_DOTS_BLOBS blobs_big; + memset(&blobs_big, 0x00, sizeof(ERROR_DOTS_BLOBS)); + ERROR_DOTS_BLOBS blobs_big_2; + memset(&blobs_big_2, 0x00, sizeof(ERROR_DOTS_BLOBS)); + printf("=====>>>> GetALLBlob m_strCurDetChannel %s \n", m_strCurDetChannel.c_str()); + if (m_strCurDetChannel == "CA") + { + printf("=====>>>>GetALLBlob USE CA %s \n", m_strCurDetChannel.c_str()); + GetBlobs_ALL_New(&blobs_v1, pGrayErrordata, m_ImgBlobHFlagData, width, height, 15); + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 1 num %d", blobs_v1.blobCount); + + if (blobs_v1.srcBlobCount >= _MAX_ERROR_DOT_BLOB) + { + + GetBlobs_ALL_New(&blobs_big, pGrayErrordata, m_ImgBlobHFlagData, width, height, 200); + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 2 num %d", blobs_big.blobCount); + + if (blobs_big.srcBlobCount >= _MAX_ERROR_DOT_BLOB) + { + + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 3 num %d", blobs_big_2.blobCount); + GetBlobs_ALL_New(&blobs_big_2, pGrayErrordata, m_ImgBlobHFlagData, width, height, 500); + } + } + } + else + { + GetBlobs_oneLabe(&blobs_v1, pGrayErrordata, m_ImgBlobHFlagData, width, height, 15); + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 1 num %d", blobs_v1.blobCount); + + if (blobs_v1.srcBlobCount >= _MAX_ERROR_DOT_BLOB) + { + + GetBlobs_oneLabe(&blobs_big, pGrayErrordata, m_ImgBlobHFlagData, width, height, 200); + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 2 num %d", blobs_big.blobCount); + + if (blobs_big.srcBlobCount >= _MAX_ERROR_DOT_BLOB) + { + + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 3 num %d", blobs_big_2.blobCount); + GetBlobs_oneLabe(&blobs_big_2, pGrayErrordata, m_ImgBlobHFlagData, width, height, 500); + } + } + } + + long t2 = CheckUtil::getcurTime(); + PushBlob(&blobs, &blobs_big_2); + PushBlob(&blobs, &blobs_big); + PushBlob(&blobs, &blobs_v1); + + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob ALL num %d", blobs.blobCount); + // long t2 = CheckUtil::getcurTime(); + // printf(" BLob time %ld \n", t2 - t1); + + if (false || DetImgInfo_shareP->bsaveProcessImg) + { + int font_face = cv::FONT_HERSHEY_SIMPLEX; + double font_scale = 0.5; + int thickness = 1; + + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, "Save Tem Img"); + cv::Mat tm; + cv::cvtColor(m_pImageAllResult->AIMaskImg, tm, cv::COLOR_GRAY2RGB); // 彩色 可选项 + for (int i = 0; i < blobs.blobCount; i++) + { + cv::Rect roi; + roi.x = blobs.blobTab[i].minx; + roi.y = blobs.blobTab[i].miny; + roi.width = blobs.blobTab[i].maxx - blobs.blobTab[i].minx + 1; + roi.height = blobs.blobTab[i].maxy - blobs.blobTab[i].miny + 1; + + if (blobs.blobTab[i].ErrType == 0) + { + cv::rectangle(tm, roi, cv::Scalar(0, 0, 255)); + } + else + { + cv::rectangle(tm, roi, cv::Scalar(0, 255, 255)); + } + + char buffer[128]; + sprintf(buffer, "id:%d type:%d m %0.1f", i,blobs.blobTab[i].ErrType, blobs.blobTab[i].density); + std::string text = buffer; + cv::Point origin = cv::Point(roi.x, roi.y); + cv::putText(tm, text, origin, font_face, font_scale, cv::Scalar(0, 255, 0), thickness, 1, 0); + + // printf("type: %d %d %d %d %d %d %d\n", blobs.blobTab[i].ErrType, blobs.blobTab[i].area, blobs.blobTab[i].energy, roi.x, roi.y, roi.width, roi.height); + } + cv::imwrite(m_CheckResult_shareP->in_shareImage->strChannel + "_image_resize_blob.png", tm); + } + + long te = CheckUtil::getcurTime(); + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "image Blob Analysis End use time %ld blob %ld ms", te - t1, t2 - t1); + + // getchar(); + return 0; +} + +int ImgCheckAnalysisy::AIMaskDet() +{ + + // 计算 mask 图片的一行 是否有 残点,用以加速 Blob的计算。 + if (m_ImgBlobHFlagData) + { + delete[] m_ImgBlobHFlagData; + m_ImgBlobHFlagData = NULL; + } + m_ImgBlobHFlagData = new unsigned char[m_pImageAllResult->detImg.rows]; + memset(m_ImgBlobHFlagData, 0, sizeof(unsigned char) * m_pImageAllResult->detImg.rows); + + while (true) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::shared_ptr AImaskResult; + { + std::lock_guard lock(mtx_AIMaskImgBLobQueue); + if (m_AIMaskImgBLobQueue.size() > 0) + { + AImaskResult = std::move(m_AIMaskImgBLobQueue.front()); + m_AIMaskImgBLobQueue.pop(); + // printf("size ============== %ld\n", m_AIMaskImgBLobQueue.size()); + } + } + + // 有AI mask 的结果 + if (AImaskResult) + { + // static int ss = 0; + cv::Mat &outimg = *(AImaskResult->output); + // cv::imwrite(std::to_string(ss++) + ".png", outimg); + + unsigned char *pGrayErrordata = (unsigned char *)outimg.data; + int width = outimg.cols; + int height = outimg.rows; + int start_Y = AImaskResult->roi.y; + if (cv::countNonZero(outimg != 0) != 0) + { + // #pragma omp parallel for + for (int y = 0; y < height; y++) + { + if (m_ImgBlobHFlagData[y + start_Y] == 0) + { + unsigned char *p = pGrayErrordata + y * width; + for (int x = 0; x < width; x++) + { + if (p[x] != 0) + { + m_ImgBlobHFlagData[y + start_Y] = 1; + break; + } + } + } + } + } + } + else + { + /* code */ + + if (m_AItask->isComplate()) + { + break; + } + } + } + // printf("===========================================1 \n"); + m_AItask->waitComplate(); + int rec = m_AItask->nresult; + if (rec != CHECK_OK) + { + return rec; + } + // printf("===========================================2 \n"); + return 0; +} + +int ImgCheckAnalysisy::Contours() +{ + // std::string strBaseLog = "Contours"; + // // m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Contours Start"); + // cv::Mat detimg; + // { + // // 膨胀 + // cv::Mat se = getStructuringElement(0, Size(5, 5)); // 构造矩形结构元素 + // cv::dilate(m_pdetlog->temImgList[TEM_IMG_IDX_AImask], detimg, se); + // } + + // std::vector> contours; + // std::vector hierarchy; + // cv::findContours(detimg, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); // 只找最外层轮廓 + + // // cv::cvtColor(m_pdetlog->temImgList[TEM_IMG_IDX_SrcCrop], m_pdetlog->temImgList[TEM_IMG_IDX_DrawSrc], cv::COLOR_GRAY2BGR); + + // for (int i = 0; i < contours.size(); ++i) + // { // 绘制所有轮廓 + // cv::drawContours(m_pdetlog->temImgList[TEM_IMG_IDX_DrawSrc], contours, i, cv::Scalar(255, 0, 255)); // thickness为-1时为填充整个轮廓 + // } + + // float fx = m_pdetlog->temImgList[TEM_IMG_IDX_Result].cols * 1.0f / m_pdetlog->temImgList[TEM_IMG_IDX_SrcCrop].cols; + // float fy = m_pdetlog->temImgList[TEM_IMG_IDX_Result].rows * 1.0f / m_pdetlog->temImgList[TEM_IMG_IDX_SrcCrop].rows; + // for (int i = 0; i < contours.size(); ++i) + // { + // for (int j = 0; j < contours.at(i).size(); ++j) + // { + // contours.at(i).at(j).x *= fx; + // contours.at(i).at(j).y *= fy; + // } + // } + // // cv::cvtColor(m_pdetlog->temImgList[TEM_IMG_IDX_Result], m_pdetlog->temImgList[TEM_IMG_IDX_Result], cv::COLOR_GRAY2BGR); + + // for (int i = 0; i < contours.size(); ++i) + // { // 绘制所有轮廓 + // cv::drawContours(m_pdetlog->temImgList[TEM_IMG_IDX_Result], contours, i, cv::Scalar(255, 0, 255)); // thickness为-1时为填充整个轮廓 + // } + // cv::imwrite("TEM_IMG_IDX_Result.png", m_pdetlog->temImgList[TEM_IMG_IDX_Result]); + // cv::imwrite("deeeee.png", m_pdetlog->temImgList[TEM_IMG_IDX_Drawmask]); + // getchar(); + // m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Contours End"); + return 0; +} + +int ImgCheckAnalysisy::CheckImgInit() +{ + // 1、初始化 + + m_pDetResult->pQx_ErrorList = std::make_shared>(); + m_pdetlog->Init(); + m_pdetlog->addLogLevel = DET_LOG_LEVEL_3; + memset(&blobs, 0, sizeof(ERROR_DOTS_BLOBS)); + m_nCheckResultErrorCode = 0; + + m_Draw_qxImageResult.erase(m_Draw_qxImageResult.begin(), m_Draw_qxImageResult.end()); + + m_DetRoiList.Init(); + + return 0; +} + +int ImgCheckAnalysisy::ConfigCheck(cv::Mat img) +{ + + m_pdetlog->AddCheckstr(PrintLevel_0, "start", "Config Check"); + int re = CHECK_OK; + if (img.empty()) + { + m_nErrorCode = CHECK_ERROR_CheckImg_Empty; + m_pdetlog->AddCheckstr(PrintLevel_1, "Error", "check Img empty"); + return m_nErrorCode; + } + + // if (m_pCommonAnalysisyConfig->regionConfigArr.size() <= 0) + // { + // m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Error", "regionConfig Num = 0"); + // m_nErrorCode = CHECK_ERROR_Config_Value; + // return m_nErrorCode; + // } + + m_pdetlog->AddCheckstr(PrintLevel_0, "Succ", "Config Check Succ"); + return re; +} + +int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg) +{ + std::shared_ptr pAIDet; + // printf("=====>>>>AI_Detect_Thread m_strCurDetChannel %s \n", m_strCurDetChannel.c_str()); + if (m_strCurDetChannel == "CA") + { + // printf("=====>>>>AI_Detect_Thread USE CA %s \n", m_strCurDetChannel.c_str()); + pAIDet = AI_Factory->CELL_CA_Det; + } + else + { + pAIDet = AI_Factory->CELL_TA_Det; + } + + std::string strBaseLog = "AI_Detect"; + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "AI_Detect Start"); + long t1, t2, t3; + t1 = CheckUtil::getcurTime(); + + SmallRoiList.clear(); + SmallRoiList.erase(SmallRoiList.begin(), SmallRoiList.end()); + cv::Rect cutRoi; + cutRoi.x = 0; + cutRoi.y = 0; + cutRoi.width = img.cols - 0; + cutRoi.height = img.rows - 0; + + int deal_image_width = pAIDet->input_0.width; + int deal_image_height = pAIDet->input_0.height; + + int re = CheckUtil::cutSmallImg(img, SmallRoiList, cutRoi, deal_image_width, deal_image_height, 0, 0); + + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, " cutSmallImg Num %d", SmallRoiList.size()); + if (re != 0 || SmallRoiList.size() <= 0) + { + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, " cutSmallImg error %d", re); + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "AI_Detect End"); + return re; + /* code */ + } + + // 临时存图 + if (DetImgInfo_shareP->bsaveProcessImg) + { + + cv::Mat imshow; + if (img.channels() == 1) + { + cv::cvtColor(img, imshow, cv::COLOR_GRAY2RGB); // 彩色 可选项 + } + else + { + imshow = img.clone(); + } + for (int i = 0; i < SmallRoiList.size(); i++) + { + cv::rectangle(imshow, SmallRoiList.at(i), cv::Scalar(0, 0, 255), 3); + } + cv::imwrite(DetImgInfo_shareP->strChannel + "_AI_Det_ROI.jpg", imshow); + } + + ResultImg = cv::Mat::zeros(img.size(), CV_8UC1); + + const int totalTasks = SmallRoiList.size(); + int submitted = 0; + int completed = 0; + + // std::string str_Root = m_strRootPath + pDetConfig->strProductID + "_" + pDetConfig->strchannel + "_"; + t2 = CheckUtil::getcurTime(); + while (completed < totalTasks) + { + // 如果任务还没提交完,且当前处理任务数 < 2,提交新任务 + if (submitted < totalTasks && runner->GetProcessingCount() < 10) + { + + std::shared_ptr task = std::make_shared(); + task->id = completed; + task->roi = SmallRoiList.at(submitted); + task->input = img(SmallRoiList.at(submitted)).clone(); + task->output = std::make_shared(); + task->engine = pAIDet; + + runner->SubmitTask(task); + submitted++; + } + + // 尝试取结果 + std::shared_ptr result; + if (runner->PopResult(result)) + { + + { + std::lock_guard lock(mtx_AIMaskImgBLobQueue); + m_AIMaskImgBLobQueue.push(result); + } + + cv::Mat &outimg = *(result->output); + if (!outimg.empty()) + { + outimg.copyTo(ResultImg(result->roi), outimg); + } + { + std::shared_ptr temAIresult = std::make_shared(); + temAIresult->roi = result->roi; + temAIresult->AI_inImg = result->input; + temAIresult->AI_mask = outimg; + m_pImageAllResult->AI_Qx_MaskList.push_back(temAIresult); + } + completed++; + } + else + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + } + + t3 = CheckUtil::getcurTime(); + float mean_AI = (t3 - t2) / SmallRoiList.size(); + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, " AI Run Time: sum %ld pre %ld Run %ld mean One Small Img %f", t3 - t1, t2 - t1, t3 - t2, mean_AI); + + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "AI_Detect End"); + + // 临时存图 + if (DetImgInfo_shareP->bsaveProcessImg) + { + cv::imwrite(DetImgInfo_shareP->strChannel + "_AI_mask.png", ResultImg); + } + + // getchar(); + return 0; +} + +int ImgCheckAnalysisy::AI_QX_Class_Thread() +{ + + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "QX_Class", " Start"); + + std::shared_ptr pAIDet; + // printf("=====>>>>AI_QX_Class_Thread m_strCurDetChannel %s \n", m_strCurDetChannel.c_str()); + if (m_strCurDetChannel == "CA") + { + // printf("=====>>>>AI_QX_Class_Thread USE CA %s \n", m_strCurDetChannel.c_str()); + pAIDet = AI_Factory->CELL_CA_Cls; + } + else + { + pAIDet = AI_Factory->CELL_TA_Cls; + } + + int deal_image_width = pAIDet->input_0.width; + int deal_image_height = pAIDet->input_0.height; + + const int totalTasks = blobs.blobCount; + int submitted = 0; + int completed = 0; + int detblobIdx = 0; + int clsnum = 0; + // std::string str_Root = m_strRootPath + pDetConfig->strProductID + "_" + pDetConfig->strchannel + "_"; + long t2 = CheckUtil::getcurTime(); + while (completed < totalTasks) + { + // std::this_thread::sleep_for(std::chrono::milliseconds(1)); + if (submitted < totalTasks) + { + ERROR_DOTS_BLOB_DATA *pblob = &blobs.blobTab[submitted]; + if (pblob->ErrType == ERR_TYPE_2) + { + pblob->AIclasstype = CONFIG_QX_NAME_cell_ymhs; + submitted++; + completed++; + continue; + } + else + { + // 如果任务还没提交完,且当前处理任务数 < 2,提交新任务 + if (runner->GetProcessingCount() < 10) + { + clsnum++; + cv::Rect roi; + roi.x = pblob->minx; + roi.y = pblob->miny; + roi.width = pblob->maxx - pblob->minx + 1; + roi.height = pblob->maxy - pblob->miny + 1; + + std::shared_ptr task = std::make_shared(); + task->id = submitted; + int re = GetClassImg(m_pImageAllResult->detImg, task->input, roi, deal_image_width, deal_image_height); + if (re == 0) + { + task->bclass = true; + task->engine = pAIDet; + runner->SubmitTask(task); + } + else + { + completed++; + } + + submitted++; + } + } + } + + // 尝试取结果 + std::shared_ptr result; + if (runner->PopResult(result)) + { + + int temClass = result->cls_label; + int cls_num = 0; + + switch (temClass) + { + case 0: + cls_num = AI_CLass_QX_NAME_aotudian; + break; + + case 1: + cls_num = AI_CLass_QX_NAME_other; + break; + + case 2: + cls_num = AI_CLass_QX_NAME_line; + break; + + case 3: + cls_num = AI_CLass_QX_NAME_zangwu; + break; + + case 4: + cls_num = AI_CLass_QX_NAME_dianzhuang; + break; + + case 5: + cls_num = AI_CLass_QX_NAME_posun; + break; + + case 6: + cls_num = AI_CLass_QX_NAME_xianwei; + break; + + case 7: + cls_num = AI_CLass_QX_NAME_shuizi; + break; + + case 8: + cls_num = AI_CLass_QX_NAME_danban; + break; + + case 9: + cls_num = AI_CLass_QX_NAME_fuchen; + break; + + default: + cls_num = AI_CLass_QX_NAME_zangwu; + break; + } + + // std::string strclassName = AI_CLass_QX_NAME_Names[cls_num]; + // printf("AI Class num %d = %s %f\n", cls_num, strclassName.c_str(), result->cls_score); + + // 分类存图 开启。 + if (m_pbaseCheckFunction->saveImg.bSaveAlginImg) + { + + std::string saveimgpaht = ""; + + if (m_strCurDetChannel == "TA") + { + saveimgpaht = m_strRootPath_TA_cls + std::to_string(cls_num) + "/" + std::to_string(CheckUtil::getcurTime()) + "_" + std::to_string(result->cls_score) + ".png"; + } + else + { + saveimgpaht = m_strRootPath_CA_cls + std::to_string(cls_num) + "/" + std::to_string(CheckUtil::getcurTime()) + "_" + std::to_string(result->cls_score) + ".png"; + } + + { + m_pImageStorage->addImage(saveimgpaht, result->input); + } + } + + int configqx = AIClassTypeToConfigType(cls_num); + + ERROR_DOTS_BLOB_DATA *pblob = &blobs.blobTab[result->id]; + pblob->AIclasstype = configqx; + + completed++; + } + else + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + } + // printf("=====>>>>AI_QX_Class_Thread clsnum %d \n", clsnum); + return 0; +} + +int ImgCheckAnalysisy::ThreadTask(int nId) +{ + + while (!m_bExit) + { + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + // 等待是否有任务 + std::shared_ptr task = m_task.GetTask(); + + // 把任务发送给对应的任务处理函数进行处理 + switch (task->taskname) + { + case Task_AI: + TaskFun_AIDet(task); + break; + case Task_Class: + TaskFun_QxClass(task); + break; + default: + break; + } + } + return 0; +} + +int ImgCheckAnalysisy::ResizeImg() +{ + + cv::Size sz; + sz.width = RESIZE_IMAGE_WIDTH; + + float fw = RESIZE_IMAGE_WIDTH * 1.0f / m_pImageAllResult->detImg.cols; + sz.height = int(m_pImageAllResult->detImg.rows * fw); + + cv::resize(m_pImageAllResult->detImg, m_pImageAllResult->resultImg, sz); + if (m_pImageAllResult->resultImg.channels() == 1) + { + cv::cvtColor(m_pImageAllResult->resultImg, m_pImageAllResult->resultImg, cv::COLOR_GRAY2BGR); + } + m_CheckResult_shareP->resultimg = m_pImageAllResult->resultImg; + m_pdetlog->AddCheckstr(PrintLevel_1, "showImg size", " [w %d,h %d]-> show img [w %d,h %d] ", + m_CutRoi.width, m_CutRoi.height, sz.width, sz.height); + return 0; +} + +void ImgCheckAnalysisy::TaskFun_AIDet(std::shared_ptr task) +{ + task->SetStatus(TaskStep_run); + long t1, t2; + // AI 推理生成 + { + t1 = CheckUtil::getcurTime(); + + int rec = AI_Detect_Thread(m_pImageAllResult->detImg, m_pImageAllResult->AIMaskImg); + + t2 = CheckUtil::getcurTime(); + task->nresult = rec; + } + task->SetStatus(TaskStep_compate); +} + +void ImgCheckAnalysisy::TaskFun_QxClass(std::shared_ptr task) +{ + task->SetStatus(TaskStep_run); + long t1, t2; + // AI 推理生成 + { + t1 = CheckUtil::getcurTime(); + + int rec = AI_QX_Class_Thread(); + + t2 = CheckUtil::getcurTime(); + task->nresult = rec; + } + task->SetStatus(TaskStep_compate); +} + +int ImgCheckAnalysisy::Update_DetRoiList() +{ + float fx = m_pImageAllResult->fscale_detToresult_x; + float fy = m_pImageAllResult->fscale_detToresult_y; + + int num = 0; + cv::Rect offsetroi = m_Crop_Roi_paramImg; + + if (m_pEdge_Align_Result && m_pEdge_Align_Result->buseOfft) + { + for (const auto ®ion : m_pCommonAnalysisyConfig->regionConfigArr) + { + + if (m_pEdge_Align_Result->H.empty()) + { + + m_DetRoiList.Update_1(region.basicInfo.pointArry, offsetroi, m_pEdge_Align_Result->offt_x, m_pEdge_Align_Result->offt_y, fx, fy); + } + else + { + + m_DetRoiList.Update_Marit(region.basicInfo.pointArry, offsetroi, m_pEdge_Align_Result->H, fx, fy); + } + + // m_DetRoiList.Update_1(region.basicInfo.pointArry, offsetroi, m_pEdge_Align_Result->offt_x, m_pEdge_Align_Result->offt_y, fx, fy); + } + } + else + { + for (const auto ®ion : m_pCommonAnalysisyConfig->regionConfigArr) + { + m_DetRoiList.Update(region.basicInfo.pointArry, m_Crop_Roi_paramImg, fx, fy); + } + } + + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "info", "roiList_Src roi num %ld", m_DetRoiList.roiList_Src.size()); + // m_DetRoiList.print("m_DetRoiList"); + return 0; +} + +int ImgCheckAnalysisy::DrawResult_Step_1() +{ + + // std::cout << m_pBasicConfig->bDrawPreRoi << std::endl; + if (m_pBasicConfig->bDrawPreRoi) + { + int n = 0; + // std::cout << m_DetRoiList.roiList_Show.size() << std::endl; + for (const auto &polygon : m_DetRoiList.roiList_Show) + { + // n++; + // if (n == 1) + // { + // continue; + // } + + // std::cout << polygon << std::endl; + + // 绘制多边形的边界(不填充),使用绿色线条,线宽为2 + cv::polylines(m_CheckResult_shareP->resultimg, polygon, true, cv::Scalar(128, 128, 255), 1); // true表示闭合多边形 + } + // cv::imwrite(DetImgInfo_shareP->strChannel + "roi_src.png", m_pdetlog->temImgList[TEM_IMG_IDX_DrawSrc]); + // cv::imwrite(DetImgInfo_shareP->strChannel + "roi_ss.png", m_pdetlog->temImgList[TEM_IMG_IDX_Result]); + + // getchar(); + } + + float fs_resize_x = m_pImageAllResult->resultImg.cols * 1.0f / m_pImageAllResult->detImg.cols; + float fs_resize_y = m_pImageAllResult->resultImg.rows * 1.0f / m_pImageAllResult->detImg.rows; + + // 要绘制结果 + if (m_pbaseCheckFunction && m_pbaseCheckFunction->edgeDet.bDrawResult) + { + for (const auto &r : m_Edge_DetConfig.edge_det_roi) + { + cv::Rect droi; + droi.x = r.roi.x * fs_resize_x; + droi.y = r.roi.y * fs_resize_y; + droi.width = r.roi.width * fs_resize_x; + droi.height = r.roi.height * fs_resize_y; + + cv::rectangle(m_CheckResult_shareP->resultimg, droi, cv::Scalar(255, 0, 255), 1); // 黄色角点 + } + + if (m_Edge_DetConfig.Det_region.size() > 2) + { + for (int i = 0; i < m_Edge_DetConfig.Det_region.size() - 1; i++) + { + cv::Point p1; + p1.x = m_Edge_DetConfig.Det_region[i].x * fs_resize_x; + p1.y = m_Edge_DetConfig.Det_region[i].y * fs_resize_y; + cv::Point p2; + p2.x = m_Edge_DetConfig.Det_region[i + 1].x * fs_resize_x; + p2.y = m_Edge_DetConfig.Det_region[i + 1].y * fs_resize_y; + cv::line(m_CheckResult_shareP->resultimg, p1, p2, cv::Scalar(0, 255, 255)); + } + { + cv::Point p1; + p1.x = m_Edge_DetConfig.Det_region[0].x * fs_resize_x; + p1.y = m_Edge_DetConfig.Det_region[0].y * fs_resize_y; + cv::Point p2; + p2.x = m_Edge_DetConfig.Det_region[m_Edge_DetConfig.Det_region.size() - 1].x * fs_resize_x; + p2.y = m_Edge_DetConfig.Det_region[m_Edge_DetConfig.Det_region.size() - 1].y * fs_resize_y; + cv::line(m_CheckResult_shareP->resultimg, p1, p2, cv::Scalar(0, 255, 255)); + } + } + } + if (m_pbaseCheckFunction && m_pbaseCheckFunction->markLine.region.size() > 1) + { + std::vector product_roi_show; + for (const auto &pt : m_pbaseCheckFunction->markLine.region) + { + cv::Point draw_pt; + draw_pt.x = (pt.x - m_Crop_Roi_paramImg.x) * fs_resize_x; + draw_pt.y = (pt.y - m_Crop_Roi_paramImg.y) * fs_resize_y; + product_roi_show.push_back(draw_pt); + } + + cv::polylines( + m_CheckResult_shareP->resultimg, + product_roi_show, + true, + cv::Scalar(0, 255, 0), + 1); + } + if (m_pEdge_Align_Result.get() != NULL) + { + + if (m_pbaseCheckFunction->markLine.bDraw) + { + for (size_t i = 0; i < m_pEdge_Align_Result->markresulList.size(); i++) + { + // if (m_pEdge_Align_Result->markresulList[i].status == Mark_Result_Status_OK) + { + cv::Point p; + p.x = m_pEdge_Align_Result->markresulList[i].det_Local_DetImg.x * fs_resize_x; + p.y = m_pEdge_Align_Result->markresulList[i].det_Local_DetImg.y * fs_resize_y; + cv::circle(m_CheckResult_shareP->resultimg, p, 5, cv::Scalar(0, 255, 0)); + } + } + } + } + + // cv::imwrite("sss.png", m_CheckResult_shareP->resultimg); + return 0; +} + +int ImgCheckAnalysisy::AIClassTypeToConfigType(int nAIQXType) +{ + + int resultError_type = CONFIG_QX_NAME_cell_aotudian; + switch (nAIQXType) + { + case AI_CLass_QX_NAME_aotudian: + resultError_type = CONFIG_QX_NAME_cell_aotudian; + break; + case AI_CLass_QX_NAME_other: + resultError_type = CONFIG_QX_NAME_cell_other; + break; + case AI_CLass_QX_NAME_line: + resultError_type = CONFIG_QX_NAME_cell_line; + break; + case AI_CLass_QX_NAME_zangwu: + resultError_type = CONFIG_QX_NAME_cell_zangwu; + break; + case AI_CLass_QX_NAME_dianzhuang: + resultError_type = CONFIG_QX_NAME_cell_dianzhuang; + break; + case AI_CLass_QX_NAME_posun: + resultError_type = CONFIG_QX_NAME_cell_posun; + break; + case AI_CLass_QX_NAME_xianwei: + resultError_type = CONFIG_QX_NAME_cell_xianwei; + break; + case AI_CLass_QX_NAME_shuizi: + resultError_type = CONFIG_QX_NAME_cell_shuizi; + break; + case AI_CLass_QX_NAME_danban: + resultError_type = CONFIG_QX_NAME_cell_danban; + break; + case AI_CLass_QX_NAME_fuchen: + resultError_type = CONFIG_QX_NAME_cell_fuchen; + break; + default: + break; + } + return resultError_type; +} + +int ImgCheckAnalysisy::UpdateImgageScale() +{ + + if (m_pBasicConfig->fImage_Scale_x > 0 && m_pBasicConfig->fImage_Scale_x < 1 && + m_pBasicConfig->fImage_Scale_y > 0 && m_pBasicConfig->fImage_Scale_y < 1) + { + + m_fImgage_Scale_X = m_pBasicConfig->fImage_Scale_x; + m_fImgage_Scale_Y = m_pBasicConfig->fImage_Scale_y; + } + + return 0; +} + +int ImgCheckAnalysisy::Edge_Qx_Det(const cv::Mat &img) +{ + + m_Edge_DetConfig.Init(); + m_Edge_DetConfig.strChannel = m_strCurDetChannel; + m_Edge_DetConfig.pBaseCheckFunction = m_pbaseCheckFunction; + m_Edge_DetConfig.alginResult.corpRoi = m_Crop_Roi_paramImg; + + if (m_pEdge_Align_Result && m_pEdge_Align_Result->buseOfft) + { + m_Edge_DetConfig.alginResult.offtx = m_pEdge_Align_Result->offt_x; + m_Edge_DetConfig.alginResult.offty = m_pEdge_Align_Result->offt_y; + m_Edge_DetConfig.alginResult.H = m_pEdge_Align_Result->H.clone(); + } + m_Edge_DetConfig.bSaveResultImg = false; + if (DetImgInfo_shareP->bsaveProcessImg) + { + m_Edge_DetConfig.bSaveResultImg = true; + } + // m_pbaseCheckFunction->print("Edge_Qx_Det"); + int re = m_Edge_QX_Det.Detect(img, &m_Edge_DetConfig); + if (re == 0) + { + for (const auto r : m_Edge_DetConfig.qx_result) + { + QX_ERROR_INFO_ temerror; + temerror.roi = r.roi_src; + temerror.Idx = m_pDetResult->pQx_ErrorList->size(); + temerror.area = r.area_pixel; + temerror.JudgArea = r.area_pixel * m_fImgage_Scale_X * m_fImgage_Scale_Y; + temerror.JudgArea_second = temerror.JudgArea; + temerror.energy = 99999999; + temerror.flen = std::max(r.roi_src.width, r.roi_src.height); + temerror.fbreadth = std::min(r.roi_src.width, r.roi_src.height); + temerror.nconfig_qx_type = CONFIG_QX_NAME_cell_edge; + temerror.qx_name = CONFIG_QX_NAME_Names[CONFIG_QX_NAME_cell_edge]; + temerror.maxValue = 0; + temerror.grayDis = 255; + temerror.density = 0; + temerror.fUpIou = 0; + + { + cv::Point pCenter; + pCenter.x = temerror.roi.x + temerror.roi.width * 0.5; + pCenter.y = temerror.roi.y + temerror.roi.height * 0.5; + int nmaxregionIdx = 0; + for (int iregion = 0; iregion < m_DetRoiList.roiList_Src.size(); iregion++) + { + const std::vector &polygon = m_DetRoiList.roiList_Src[iregion]; + double result = cv::pointPolygonTest(polygon, pCenter, false); + if (result < 0) + { + continue; + } + nmaxregionIdx = iregion; + } + + temerror.detRegionidxList.push_back(nmaxregionIdx); + } + + // { + // cv::Point pCenter; + // pCenter.x = temerror.roi.x + temerror.roi.width * 0.5; + // pCenter.y = temerror.roi.y + temerror.roi.height * 0.5; + // int nmaxregionIdx = 0; + // for (int iregion = 0; iregion < m_DetRoiList.roiList_Src.size(); iregion++) + // { + // const std::vector &polygon = m_DetRoiList.roiList_Src[iregion]; + // double result = cv::pointPolygonTest(polygon, pCenter, false); + // if (result < 0) + // { + // continue; + // } + // temerror.detRegionidxList.push_back(iregion); + // } + // if (temerror.detRegionidxList.size() <= 0) + // { + // temerror.detRegionidxList.push_back(0); + // } + // } + + m_pDetResult->pQx_ErrorList->push_back(temerror); + } + + m_pdetlog->AddCheckstr(PrintLevel_1, "Edge_Qx_Det", " succ qx num %ld", m_Edge_DetConfig.qx_result.size()); + // printf("- %s idx %d a %f v %d h %f l %f\n", DetImgInfo_shareP->strChannel.c_str(), i, JudgArea, blobs.blobTab[i].maxValue, blobs.blobTab[i].grayDis, flen); + } + else + { + m_pdetlog->AddCheckstr(PrintLevel_1, "Edge_Qx_Det", " error %d", re); + } + + return 0; +} + +int ImgCheckAnalysisy::BLobToDetResult() +{ + long t1 = CheckUtil::getcurTime(); + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "BLobToDetResult", " Start old qx num %ld", m_pDetResult->pQx_ErrorList->size()); + + // 遍历每个检测blob + for (int i = 0; i < blobs.blobCount; i++) + { + cv::Rect roi; + roi.x = blobs.blobTab[i].minx; + roi.y = blobs.blobTab[i].miny; + roi.width = blobs.blobTab[i].maxx - blobs.blobTab[i].minx + 1; + roi.height = blobs.blobTab[i].maxy - blobs.blobTab[i].miny + 1; + + int config_qx_type = blobs.blobTab[i].AIclasstype; + + float JudgArea = blobs.blobTab[i].JudgArea; + float fsecondArea = JudgArea; + std::string qx_name = CONFIG_QX_NAME_Names[config_qx_type]; + + if (true) + { + QX_ERROR_INFO_ temerror; + temerror.roi = roi; + temerror.Idx = m_pDetResult->pQx_ErrorList->size(); + temerror.area = blobs.blobTab[i].area; + temerror.JudgArea = JudgArea; + temerror.JudgArea_second = fsecondArea; + temerror.energy = blobs.blobTab[i].energy; + temerror.flen = blobs.blobTab[i].len; + temerror.fbreadth = blobs.blobTab[i].breadth; + temerror.nconfig_qx_type = config_qx_type; + temerror.qx_name = qx_name; + temerror.maxValue = blobs.blobTab[i].maxValue; + temerror.grayDis = blobs.blobTab[i].grayDis; + temerror.density = blobs.blobTab[i].density; + temerror.fUpIou = 0; + temerror.whiteOrBlack = blobs.blobTab[i].whiteOrblack; + + { + cv::Point pCenter; + pCenter.x = roi.x + roi.width * 0.5; + pCenter.y = roi.y + roi.height * 0.5; + int nmaxregionIdx = 0; + for (int iregion = 0; iregion < m_DetRoiList.roiList_Src.size(); iregion++) + { + const std::vector &polygon = m_DetRoiList.roiList_Src[iregion]; + double result = cv::pointPolygonTest(polygon, pCenter, false); + if (result < 0) + { + continue; + } + nmaxregionIdx = iregion; + } + + temerror.detRegionidxList.push_back(nmaxregionIdx); + } + + // { + // cv::Point pCenter; + // pCenter.x = roi.x + roi.width * 0.5; + // pCenter.y = roi.y + roi.height * 0.5; + // for (int iregion = 0; iregion < m_DetRoiList.roiList_Src.size(); iregion++) + // { + // const std::vector &polygon = m_DetRoiList.roiList_Src[iregion]; + // double result = cv::pointPolygonTest(polygon, pCenter, false); + // if (result < 0) + // { + // continue; + // } + // temerror.detRegionidxList.push_back(iregion); + // } + // if (temerror.detRegionidxList.size() <= 0) + // { + // temerror.detRegionidxList.push_back(0); + // } + // } + + m_pDetResult->pQx_ErrorList->push_back(temerror); + + // printf("- %s idx %d a %f v %d h %f l %f\n", DetImgInfo_shareP->strChannel.c_str(), i, JudgArea, blobs.blobTab[i].maxValue, blobs.blobTab[i].grayDis, flen); + } + } + long t2 = CheckUtil::getcurTime(); + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "BLobToDetResult", " end qx num %ld use time %ld", m_pDetResult->pQx_ErrorList->size(), t2 - t1); + return 0; +} + +int ImgCheckAnalysisy::AI_Edge(const cv::Mat &img, cv::Rect &cutRoi) +{ + m_pdetlog->AddCheckstr(PrintLevel_0, "AI_Edge", "-------------------start--------------"); + + AI_Edge_Algin::DetConfig config; + + if (DetImgInfo_shareP->bsaveProcessImg) + { + config.bSaveResultImg = true; + } + config.strChannel = DetImgInfo_shareP->strChannel; + config.pBaseCheckFunction = m_pbaseCheckFunction; + int re = m_pAI_Edge_Algin.Detect(img, &config, m_pEdge_Align_Result); + if (re != 0) + { + printf("AI_Edge Is Error = %d \n", re); + } + cutRoi = m_pEdge_Align_Result->roi; + // getchar(); + return re; +} + +int ImgCheckAnalysisy::CalProductSize() +{ + float fw = m_CutRoi.width * m_fImgage_Scale_X; + float fh = m_CutRoi.height * m_fImgage_Scale_Y; + fw = std::ceil(fw * 10) / 10; + fh = std::ceil(fh * 10) / 10; + m_CheckResult_shareP->productWidht_mm = fw; + m_CheckResult_shareP->productHeight_mm = fh; + + m_pdetlog->AddCheckstr(PrintLevel_1, "Det ROI", " [w %d,h %d] (piexl) -> [w %f h %f](mm),scale %f %f", + m_CutRoi.width, m_CutRoi.height, fw, fh, m_fImgage_Scale_X, m_fImgage_Scale_Y); + return 0; +} + +int ImgCheckAnalysisy::ImgPreDet() +{ + + // 计算产品尺寸 + CalProductSize(); + + if (m_pbaseCheckFunction->saveImg.bSaveClsImg) + { + creatsavedir(); + } + + m_CheckResult_shareP->cutSrcimg = m_pImageAllResult->detImg; + ResizeImg(); + + m_pImageAllResult->fscale_detToresult_x = m_pImageAllResult->resultImg.cols * 1.0f / m_pImageAllResult->detImg.cols; + m_pImageAllResult->fscale_detToresult_y = m_pImageAllResult->resultImg.rows * 1.0f / m_pImageAllResult->detImg.rows; + return 0; +} diff --git a/AlgorithmModule/src/ImgCheckBase.cpp b/AlgorithmModule/src/ImgCheckBase.cpp new file mode 100644 index 0000000..2def4df --- /dev/null +++ b/AlgorithmModule/src/ImgCheckBase.cpp @@ -0,0 +1,21 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:50:00 + * @LastEditTime: 2022-09-26 16:27:27 + * @LastEditors: sueRimn + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/src/CamDeal.cpp + */ +#include "ImgCheckBase.h" +#include "ImgCheckAnalysisy.hpp" +#include "ImgCheckConfig.h" +#include "ALLImgCheckAnalysisy.hpp" +ALLImgCheckBase *ALLImgCheckBase::instance = nullptr; +ALLImgCheckBase *ALLImgCheckBase::GetInstance() +{ + // if (instance == nullptr) + // { + // instance = (ALLImgCheckBase *)new ALLImgCheckAnalysisy(); + // } + return (ALLImgCheckBase *)new ALLImgCheckAnalysisy();; +} diff --git a/AlgorithmModule/src/OtherDetect.cpp b/AlgorithmModule/src/OtherDetect.cpp new file mode 100644 index 0000000..2bfeab2 --- /dev/null +++ b/AlgorithmModule/src/OtherDetect.cpp @@ -0,0 +1,46 @@ + +#include "OtherDetect.h" +#include "CheckErrorCodeDefine.hpp" + +AIDetectBase ::AIDetectBase(/* args */) +{ + m_pOtherDet_Config = NULL; + + m_bInitialized = false; + m_bModelSucc = false; +} + +AIDetectBase ::~AIDetectBase() +{ +} +int AIDetectBase ::Init(OtherDet_Config *pOtherDet_Config) +{ + m_pOtherDet_Config = pOtherDet_Config; + + m_bInitialized = true; + return 0; +} + +LackPolDet::LackPolDet(/* args */) +{ +} + +LackPolDet::~LackPolDet() +{ +} +int LackPolDet::Init_LackPol() +{ + + + return 0; +} +int LackPolDet::InitModel_ALL() +{ + + return 0; +} +int LackPolDet::Detect(const cv::Mat &img, DetConfig *pDetConfig, cv::Mat &outMask) +{ + + return 0; +} \ No newline at end of file diff --git a/AlgorithmModule/src/Product.cpp b/AlgorithmModule/src/Product.cpp new file mode 100644 index 0000000..6d8be72 --- /dev/null +++ b/AlgorithmModule/src/Product.cpp @@ -0,0 +1,98 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-09-13 19:26:19 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-17 18:10:38 + * @FilePath: /BOE_CELL_AOI_Detect/AlgorithmModule/src/Product.cpp + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * + */ +#include "Product.h" + +Product::Product(/* args */) +{ + productBaseResult = std::make_shared(); + productBaseResult->detlog = std::make_shared(); +} + +Product::~Product() +{ +} + +std::shared_ptr Product::GetCameraResult(std::string strcameraName) +{ + // 加锁保证多线程安全 + std::lock_guard lock(mtx_CameraResultList); + for (auto &ptr : m_pCameraResultList) + { + if (ptr->cameraBaseResult->strCameraName == strcameraName) + { + return ptr; + } + } + + // 不存在,创建新的 CameraResult 并插入 map + std::shared_ptr newResult = std::make_shared(); + newResult->productBaseResult = productBaseResult; + newResult->cameraBaseResult->strCameraName = strcameraName; + m_pCameraResultList.push_back(newResult); + productBaseResult->detlog->AddCheckstr(PrintLevel_0, "PushInImg", "add new Camera %s ", strcameraName.c_str()); + return newResult; +} +void Product::AddLog(std::string str) +{ + LogList.push_back(str); +} + +void Product::UpdatePushStatus(int status) +{ + if (IN_IMG_Status_End == status || + IN_IMG_Status_OneImg == status || + -1 == status) + { + bIsImgComplete = true; + std::lock_guard lock(mtx_CameraResultList); // 加锁保护 map + + for (auto &ptr : m_pCameraResultList) + { + ptr->setImgPushComplate(); + } + std::string strTimg = CheckUtil::getCurTimeHMS(); + strEndTime = strTimg; + time_pushImg_end = CheckUtil::getcurTime(); + productBaseResult->detlog->AddCheckstr(PrintLevel_0, "PushInImg", "%s Add ALL img end %s ", productBaseResult->strproductName.c_str(), strTimg.c_str()); + } +} + +bool Product::bCheckCamplate() +{ + // 所有的图都送完了。 + if (bIsImgComplete) + { + bool ballcomplate = true; + std::lock_guard lock(mtx_CameraResultList); // 加锁保护 map + for (auto &ptr : m_pCameraResultList) + { + if (!ptr->bCheckCamplate()) + { + ballcomplate = false; + break; + } + } + if (ballcomplate) + { + return true; + } + } + + return false; +} + +void Product::SetCheckEnd() { + time_CheckImg_end = CheckUtil::getcurTime(); + product_UseAllTime = time_CheckImg_end - time_pushImg_end; + std::string strTimg = CheckUtil::getCurTimeHMS(); + + productBaseResult->detlog->AddCheckstr(PrintLevel_0, "Product", "Product Usetime %ld ms,start %s end %s",\ + product_UseAllTime, strEndTime.c_str(), strTimg.c_str()); +} diff --git a/AlgorithmModule/src/Task.cpp b/AlgorithmModule/src/Task.cpp new file mode 100644 index 0000000..7bb1d76 --- /dev/null +++ b/AlgorithmModule/src/Task.cpp @@ -0,0 +1,36 @@ +#include "Task.h" + +Task::Task() +{ +} + +Task::~Task() +{ +} + +int Task::sendTask(std::shared_ptr task) +{ + { + std::lock_guard lock(m_task_mutex_); + task->SetStatus(TaskStep_Waite); + m_tasks_.push(task); + } + + m_task_cv_.notify_one(); + return 0; +} + +std::shared_ptr Task::GetTask() +{ + std::shared_ptr task; + { + std::unique_lock lock(m_task_mutex_); + m_task_cv_.wait(lock, [this]() + { return !m_tasks_.empty(); }); + + task = std::move(m_tasks_.front()); + m_tasks_.pop(); + } + + return task; +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..41df4d0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,75 @@ +#限定CMake的版本 +cmake_minimum_required (VERSION 3.5) + +project(rootproject) +set(CHECK_WORK_Value "POL_ET") + +if (DEFINED WORK) + set(CHECK_WORK_Value ${WORK}) +endif() + +# 根据宏设置编译时宏 +add_definitions(-DCHECK_WORK="${CHECK_WORK_Value}") + +message(STATUS "CHECK_WORK: ${CHECK_WORK_Value}") + +find_package( OpenCV REQUIRED ) + +message(STATUS "oPENCV Library status:") +message(STATUS ">version:${OpenCV_VERSION}") +message(STATUS "Include:${OpenCV_INCLUDE_DIRS}") + +set(CMAKE_BUILD_TYPE "release") +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) # 要求编译器支持 C++17 +set(CMAKE_CXX_EXTENSIONS OFF) # 禁用 GNU 特定的扩展 +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +#set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS}; --default-stream per-thread) + +add_definitions(-DCUDA_API_PER_THREAD_DEFAULT_STREAM) +# PROJECT_INCLUDE_DIR当作全局头文件变量 +set(PROJECT_INCLUDE_DIR c/include) + +# x86_64,aarch64 +set(BUILD_ARCH x86_64 CACHE STRING "Arch of this project" FORCE) +MESSAGE(STATUS "BUILD_ARCH : ${BUILD_ARCH}") + +MESSAGE(STATUS "CMAKE_BUILD_TYPE : ${CMAKE_BUILD_TYPE}") +MESSAGE(STATUS "This is BINARY dir " ${PROJECT_BINARY_DIR}) +MESSAGE(STATUS "This is SOURCE dir " ${PROJECT_SOURCE_DIR}) + +#包含通用的编译环境模块到顶层目录 +include(${PROJECT_SOURCE_DIR}/cmake/default_variabes.cmake) +include(${PROJECT_SOURCE_DIR}/cmake/cpp_c_flags.cmake) +include(${PROJECT_SOURCE_DIR}/cmake/print_archs.cmake) + +include_directories(${PROJECT_SOURCE_DIR}/include/) +include_directories(/usr/local/boost/include +/usr/include +${OpenCV_INCLUDE_DIRS} +) +link_directories( +${PROJECT_SOURCE_DIR}/lib/x86_64/ +/usr/local/boost/lib +) + +#下一级的编译目录 + +MESSAGE("build dependent module - start") +#当程序执行命令 ADD_SUBDIRECTORY(src)时进入目录 src 对其中的 CMakeLists.txt 进行解析。 + +add_subdirectory(ExtractImageModule) +MESSAGE("ExtractImageModule") + + +add_subdirectory(ConfigModule) +MESSAGE("ConfigModule") + +# CommonUtil +add_subdirectory(AlgorithmModule) +MESSAGE("AlgorithmModule") + +add_subdirectory(example) +MESSAGE("example") + + diff --git a/Common/include/Base_Define.h b/Common/include/Base_Define.h new file mode 100644 index 0000000..97f2c22 --- /dev/null +++ b/Common/include/Base_Define.h @@ -0,0 +1,18 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:49:50 + * @LastEditTime: 2022-09-23 21:51:58 + * @LastEditors: sueRimn + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/include/CamDeal.h + */ +#ifndef Base_Define_H_ +#define Base_Define_H_ +#include +#include + +#define RECT_TO_STRING(rect) \ + "(x=" + std::to_string((rect).x) + ", y=" + std::to_string((rect).y) \ + + ", width=" + std::to_string((rect).width) + ", height=" + std::to_string((rect).height) + ")" + +#endif \ No newline at end of file diff --git a/ConfigModule/CMakeLists.txt b/ConfigModule/CMakeLists.txt new file mode 100644 index 0000000..a797b94 --- /dev/null +++ b/ConfigModule/CMakeLists.txt @@ -0,0 +1,42 @@ +#版本限定 +cmake_minimum_required (VERSION 3.5) + +set(ModuleName "ConfigModule") + +include(${PROJECT_SOURCE_DIR}/cmake/default_variabes.cmake) +include(${PROJECT_SOURCE_DIR}/cmake/cpp_c_flags.cmake) +include(${PROJECT_SOURCE_DIR}/cmake/print_archs.cmake) + + +#头文件 +include_directories( +/usr/local/include +${CMAKE_CURRENT_SOURCE_DIR}/include +) +link_directories( +/usr/local/lib/ +) +# 用set设置变量不能使用*.cpp +file(GLOB SRC_LISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) + +add_library(Config SHARED ${SRC_LISTS}) + +target_link_libraries(Config + ${OpenCV_LIBS} + ) +set(ModuleName "") + +#add_subdirectory(example) + +# make install 安装到/usr/local下 +# 自定义安装前缀 +set(CMAKE_INSTALL_PREFIX /usr/local/polet CACHE PATH "Install path prefix" FORCE) +set(HEADER_FILES include/ConfigBase.h) +# 安装动态库 +install(TARGETS Config + LIBRARY DESTINATION lib # 安装到 CMAKE_INSTALL_PREFIX/lib + ARCHIVE DESTINATION lib/static + RUNTIME DESTINATION bin + PUBLIC_HEADER DESTINATION include) # 安装到 CMAKE_INSTALL_PREFIX/include +# 安装头文件 +install(FILES ${HEADER_FILES} DESTINATION include) \ No newline at end of file diff --git a/ConfigModule/include/CheckConfigDefine.h b/ConfigModule/include/CheckConfigDefine.h new file mode 100644 index 0000000..101e428 --- /dev/null +++ b/ConfigModule/include/CheckConfigDefine.h @@ -0,0 +1,2191 @@ +/* + * @Descripttion: + * @version: + * @Author: sueRimn + * @Date: 2022-03-16 17:09:11 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-16 22:05:01 + */ +/***********************************************/ +/************ ***************/ +/************金佰利检测算法参数定义**************/ +/************ **************/ +/**********************************************/ +#ifndef _CheckConfigDefine_HPP_ +#define _CheckConfigDefine_HPP_ +#include +#include "ConfigBase.h" +#include + +#define MASK_IMG_STEP 16 +#define MASK_IMG_STARTVALUE 48 + +// 一个检测缺陷 最多有几组参数 +#define MASK_QX_PARAM_NUM 3 +enum REGIONTYPE_ +{ + REGION_TYPE_CHECK, // 检测区域 + REGION_TYPE_SHIELD, // 屏蔽区域 +}; +enum CONFIG_QX_WHITE_BLCAK +{ + CONFIG_QX_BLACK, // 分类 AD异显(P6873) + CONFIG_QX_WHITE, // 分类 AD异显(P6873) +}; +static const std::string WHITE_BLCAK_Names[] = + { + "black", + "white"}; +// 检测缺陷的种类 +enum CONFIG_QX_NAME_ +{ + CONFIG_QX_NAME_cell_aotudian, // 分类 凹凸点 + CONFIG_QX_NAME_cell_other, // 分类 其他 + CONFIG_QX_NAME_cell_line, // 分类 线状 + CONFIG_QX_NAME_cell_zangwu, // 分类 脏污 + CONFIG_QX_NAME_cell_edge, // 分类 边缘 + CONFIG_QX_NAME_cell_ymhs, // 分类 异物 + CONFIG_QX_NAME_cell_dianzhuang, // 分类 点状 + CONFIG_QX_NAME_cell_posun, // 分类 破损 + CONFIG_QX_NAME_cell_xianwei, // 分类 纤维 + CONFIG_QX_NAME_cell_shuizi, // 分类 水渍 + CONFIG_QX_NAME_cell_danban, // 分类 淡斑 + CONFIG_QX_NAME_cell_fuchen, // 分类 浮尘 + CONFIG_QX_NAME_count, +}; +// 缺陷项对应在参数中的名称 +static std::vector CONFIG_QX_NAME_Names = + { + "aotudian", + "other", + "line", + "zangwu", + "edge", + "ymhs", + "dianzhuang", + "posun", + "xianwei", + "shuizi", + "danban", + "fuchen", + }; + +// web控制检测的缺陷类型, +enum Function_CONFIG_QX_NAME_ +{ + Function_CONFIG_QX_NAME_ok_yisi, // 疑似 + Function_CONFIG_QX_NAME_YX, // AD异显(P6873) + Function_CONFIG_QX_NAME_line, // X_line(P3351) + Function_CONFIG_QX_NAME_zara, // ZARA(P1153) + Function_CONFIG_QX_NAME_MTX, // MTX(P1164) + Function_CONFIG_QX_NAME_POL_Cell, // 异物(P1101) + Function_CONFIG_QX_NAME_LD, // 亮点(P1112) + Function_CONFIG_QX_NAME_AD, // 暗点(P1111) + Function_CONFIG_QX_NAME_Scratch, // 划伤(P1557) + Function_CONFIG_QX_NAME_Dirty, // 脏污(P0000) + Function_CONFIG_QX_NAME_qipao, // 气泡(P0001) + Function_CONFIG_QX_NAME_PS, // ps(P0002) + Function_CONFIG_QX_NAME_Weak_Bright_Mura, // 白GAP(P1654) + Function_CONFIG_QX_NAME_No_Label, // 缺POL(P2833) + Function_CONFIG_QX_NAME_Other, // 缺POL(P2833) + Function_CONFIG_QX_NAME_Chess, // Chess 异常 + Function_CONFIG_QX_NAME_127Cell, // 白cell + Function_CONFIG_QX_NAME_Cell, // 独立检测的黑白cell点 + Function_CONFIG_QX_NAME_count, +}; +// 缺陷项对应在参数中的名称 +static const std::string Function_CONFIG_QX_NAME_Names[] = + { + "OK_Yisi", + "AD_YX", + "Line", + "ZARA", + "MXT", + "POL_Cell", + "LD", + "AnDot", + "Scratch", + "Dirty", + "Qipao", + "PS", + "Weak_Bright_Mura", + "No_Label", + "Other", + "Chess", + "Cell127", + "Cell"}; + +// 通道名称定义 +enum IMG_CHANNEL_ +{ + IMG_CHANNEL_UP, + IMG_CHANNEL_DP, + IMG_CHANNEL_L63, + IMG_CHANNEL_L127, + IMG_CHANNEL_L255, + IMG_CHANNEL_RED, + IMG_CHANNEL_GREEN, + IMG_CHANNEL_BLUE, + IMG_CHANNEL_HS, + IMG_CHANNEL_HB3, + IMG_CHANNEL_HB4, + IMG_CHANNEL_CHESS1, + IMG_CHANNEL_CHESS2, + IMG_CHANNEL_CHESS, + IMG_CHANNEL_AGO, + IMG_CHANNEL_BTW, + IMG_CHANNEL_WTB, + IMG_CHANNEL_TBW, + IMG_CHANNEL_L0, + IMG_CHANNEL_Count, +}; +// 缺陷项对应在参数中的名称 +static const std::string IMG_CHANNEL_NAME[] = + { + "Up-Particle", + "Down-Particle", + "L63", + "L127", + "L255", + "Red", + "Green", + "Blue", + "HS", + "HB3", + "HB4", + "CHESS1", + "CHESS2", + "CHESS", + "AGO", + "BTW", + "WTB", + "TBW", + "L0"}; +// 分析类型 +enum ANALYSIS_TYPE_ +{ + ANALYSIS_TYPE_TF, // 踢废 打标分析 + ANALYSIS_TYPE_YS, // 疑是 分析 + ANALYSIS_TYPE_COUNT, +}; +static const std::string ANALYSIS_TYPE_Names[] = + { + "Check_Param", + "SaveImg_Param"}; + +// 分析类型 +enum QX_RESULT_TYPE_ +{ + QX_RESULT_TYPE_OK, // 踢废 打标分析 + QX_RESULT_TYPE_NG, // 疑是 分析 + QX_RESULT_TYPE_YS, + QX_RESULT_TYPE_NoJduge, // 未判断 + QX_RESULT_TYPE_COUNT +}; +static const std::string QX_RESULT_TYPE_Names[] = + { + "OK", + "NG", + "YS", + "NoJudge"}; +// AI模型路径参数 +struct ModelConfigST +{ + std::string defect_model_path = ""; + std::string defect_wtb_model_path = ""; + std::string defect_chess_model_path = ""; + std::string YX_1_model_path = ""; + std::string YX_2_model_path = ""; + std::string zf_model_path = ""; + std::string class_model_path = ""; // 1024dyy-add + std::string class_L0_model_path = ""; // 1024dyy-add + std::string class_L255_model_path = ""; // 1024dyy-add + std::string UP_model_path = ""; // 1024dyy-add + void copy(ModelConfigST tem) + { + this->defect_model_path = tem.defect_model_path; + this->YX_1_model_path = tem.YX_1_model_path; + this->YX_2_model_path = tem.YX_2_model_path; + this->defect_wtb_model_path = tem.defect_wtb_model_path; + this->defect_chess_model_path = tem.defect_chess_model_path; + this->zf_model_path = tem.zf_model_path; + this->class_model_path = tem.class_model_path; // 1024dyy-add + this->class_L0_model_path = tem.class_L0_model_path; // 1024dyy-add + this->class_L255_model_path = tem.class_L255_model_path; // 1024dyy-add + this->UP_model_path = tem.UP_model_path; // 1024dyy-add + } + bool valid() + { + if (defect_model_path != "" && + YX_1_model_path != "" && + class_model_path != "") + { + return true; + } + return false; + } +}; +struct CAM_CONFIGINFO_ +{ + float fscale_x; + float fscale_y; // 相机分辨率 + + CAM_CONFIGINFO_() + { + fscale_x = 0.15f; + fscale_y = 0.15f; + } + void copy(CAM_CONFIGINFO_ tem) + { + this->fscale_x = tem.fscale_x; + this->fscale_y = tem.fscale_y; + } +}; +struct RegionBasicInfo +{ + std::string name; // 区域名称 + int type; // 区域类型 + int lay; // 层级 + std::vector pointArry; // 区域点 + std::vector ChannelArry; // 通道区域 + bool bdraw; // 是否绘制 + RegionBasicInfo() + { + Init(); + } + void Init() + { + name = ""; + type = 0; + lay = 0; + bdraw = false; + pointArry.clear(); + pointArry.shrink_to_fit(); + ChannelArry.clear(); + ChannelArry.shrink_to_fit(); + } + void copy(RegionBasicInfo tem) + { + this->name = tem.name; + this->type = tem.type; + this->lay = tem.lay; + this->bdraw = tem.bdraw; + this->pointArry.assign(tem.pointArry.begin(), tem.pointArry.end()); + this->ChannelArry.assign(tem.ChannelArry.begin(), tem.ChannelArry.end()); + } +}; +struct AandEParam +{ + bool bEnable; // 是否启用 + bool bOk; // 好品条件 + float area; // 面积 + float area_max; // 面积上限 + float energy; // 能量 + float hj; // 灰阶 + float length; // 长度 + float breadth; // 宽度 + int num; // 数量 + float dis; // 距离 + float density; // 密度 + AandEParam() + { + bOk = false; + bEnable = false; + area = -1; + area_max = -1; + energy = -1; + hj = -1; + length = -1; + breadth = -1; + num = -1; + dis = -1; + density = -1; + } + void print(std::string str) + { + printf("%s bEnable %d bOk %d area %f area_max %f energy %f hj %f length %f breadth %f num %d dis %f density %f \n", str.c_str(), bEnable, bOk, area, area_max, energy, hj, length, breadth, num, dis, density); + } + void copy(AandEParam tem) + { + this->bEnable = tem.bEnable; + this->bOk = tem.bOk; + this->area = tem.area; + this->area_max = tem.area_max; + this->energy = tem.energy; + this->hj = tem.hj; + this->length = tem.length; + this->breadth = tem.breadth; + this->num = tem.num; + this->dis = tem.dis; + this->density = tem.density; + } +}; + +// 区域的检测参数 +struct CheckConfig_Regions_Param +{ + + std::vector paramArr; + std::string param_name; + int useNum; // 使用个数 + CheckConfig_Regions_Param() + { + paramArr.clear(); + paramArr.shrink_to_fit(); + useNum = 0; + param_name = ""; + } + void addParam(AandEParam param) + { + paramArr.push_back(param); + useNum++; + } +}; +// 不同缺陷类型参数 +struct CheckConfig_Regions_type +{ + std::vector checkConfig_Regions_Param; +}; +// 区域相关参数 +struct RegionConfigST +{ + bool buse; // 是否使用 + RegionBasicInfo basicInfo; // 基础信息 + CheckConfig_Regions_type checkConfig_Regions_type[ANALYSIS_TYPE_COUNT]; + RegionConfigST() + { + buse = false; + } /* data */ +}; +bool compareBylay(const RegionConfigST &a, const RegionConfigST &b); +// 检测参数层级关系 +// 1、区域 +// 2、 检测项目 +// 3、 参数 阈值 + +// 阈值参数系数 +struct THRESHOLD_RATIO +{ + float farea; + float fenergy; + bool bEnable; + THRESHOLD_RATIO() + { + farea = 1; + fenergy = 1; + bEnable = false; + ; + } + void copy(THRESHOLD_RATIO tem) + { + this->farea = tem.farea; + this->fenergy = tem.fenergy; + this->bEnable = tem.bEnable; + } + void printfInfo(std::string str) + { + printf("%s bEnable %d farea %f fenergy %f \n", str.c_str(), bEnable, farea, fenergy); + } +}; + +// 区域无关的基本参数 +struct BasicConfig +{ + std::string strCamearName; + int image_widht; + int Image_height; + int width_min; // 20231122xls-add + int width_max; + int height_min; + int height_max; // 20231122xls-add + bool bDrawShieldRoi; // 绘制屏蔽区域 + bool bShield_ZF; // 屏蔽字符区域,不检测 + bool bDrawPreRoi; // 绘制弱化区域 + float fUP_IOU; + bool bCal_ImageScale; // 是否自动计算成像精度 + float Product_Size_Width_mm; // 产品尺寸 宽度 mm + float Product_Size_Height_mm; // 产品尺寸 高度 mm + float fImage_Scale_x; // 成像精度 + float fImage_Scale_y; // 成像精度 + std::string strCamName; // + + float density_R_mm; // 密度计算半径 像素 + BasicConfig() + { + Image_height = 0; + image_widht = 0; + width_min = 0; // 20231122xls-add + width_max = 999999; + height_min = 0; + height_max = 999999; + bDrawShieldRoi = false; + bShield_ZF = false; + bDrawPreRoi = false; + fUP_IOU = 0.9; + bCal_ImageScale = false; + Product_Size_Width_mm = 100; + Product_Size_Height_mm = 1000; + fImage_Scale_x = 0.03; + fImage_Scale_y = 0.03; + density_R_mm = 5; + strCamName = ""; + strCamearName = EMPTY_CONFIG_NAME; + } + void copy(BasicConfig tem) + { + this->image_widht = tem.image_widht; + this->Image_height = tem.Image_height; + this->width_min = tem.width_min; // 20231122xls-add + this->width_max = tem.width_max; + this->height_min = tem.height_min; + this->height_max = tem.height_max; + this->bDrawShieldRoi = tem.bDrawShieldRoi; + this->bShield_ZF = tem.bShield_ZF; + this->fUP_IOU = tem.fUP_IOU; + this->bDrawPreRoi = tem.bDrawPreRoi; + this->strCamName = tem.strCamName; + + this->bCal_ImageScale = tem.bCal_ImageScale; + this->Product_Size_Width_mm = tem.Product_Size_Width_mm; + this->Product_Size_Height_mm = tem.Product_Size_Height_mm; + this->fImage_Scale_x = tem.fImage_Scale_x; + this->fImage_Scale_y = tem.fImage_Scale_y; + this->density_R_mm = tem.density_R_mm; + this->strCamearName = tem.strCamearName; + } + void print(std::string str = "") + { + printf("============================↓↓↓↓↓↓%s↓↓ %s ↓↓↓↓↓=========================\n", str.c_str(), strCamearName.c_str()); + printf("bCal_ImageScale %d Product_Size_Width =%f Product_Size_Height =%f \n", bCal_ImageScale, Product_Size_Width_mm, Product_Size_Height_mm); + printf("fImage_Scale_x =%f fImage_Scale_y=%f \n", fImage_Scale_x, fImage_Scale_y); + // printf("height_min =%d height_max=%d \n", height_min, height_max); + printf("bDrawShieldRoi %d bShield_ZF %d DrawPreRoi %d fUP_IOU %f density_R_mm %f\n", bDrawShieldRoi, bShield_ZF, bDrawPreRoi, fUP_IOU, density_R_mm); + printf("============================↑↑↑↑↑↑%s↑↑↑↑↑↑=========================\n", str.c_str()); + } +}; +struct NodeBasicConfig +{ + + float calss_conf; // 分类阈值参数,低于这个阈值的不处理, + float calss_area; // 分类阈值参数,低于这个阈值的不处理, + + int img_width; + int img_height; + NodeBasicConfig() + { + + calss_conf = 0.5; + calss_area = 1.0; + } + void copy(NodeBasicConfig tem) + { + + this->calss_conf = tem.calss_conf; + this->calss_area = tem.calss_area; + } + void print(std::string str = "") + { + printf("============================↓↓↓↓↓↓%s↓↓↓↓↓↓↓=========================\n", str.c_str()); + printf("img_width %d img_height %d alss_conf %f calss_area %f \n", img_width, img_height, calss_conf, calss_area); + + printf("============================↑↑↑↑↑↑%s↑↑↑↑↑↑=========================\n", str.c_str()); + } +}; +// 多节点 +struct CommonConfigNodeST +{ + NodeBasicConfig nodebasicConfog; + std::vector regionConfigArr; + cv::Mat mask; + // cv::Mat SheildMask[IMG_CHANNEL_Count]; + void copy(CommonConfigNodeST tem) + { + this->regionConfigArr.assign(tem.regionConfigArr.begin(), tem.regionConfigArr.end()); + this->nodebasicConfog.copy(tem.nodebasicConfog); + if (!tem.mask.empty()) + { + this->mask = tem.mask.clone(); + } + // for (int i = 0; i < IMG_CHANNEL_Count; i++) + // { + // if (!tem.SheildMask[i].empty()) + // { + // this->SheildMask[i] = tem.SheildMask[i].clone(); + // } + // } + } + void InitSheildMask() { + // for (int i = 0; i < IMG_CHANNEL_Count; i++) + // { + // if (!SheildMask[i].empty()) + // { + // SheildMask[i].release(); + // } + // } + }; + void ToSheildMaskImg() + { + // printf("ToSheildMaskImg img_height %d, img_width %d\n", nodebasicConfog.img_height, nodebasicConfog.img_width); + // if (nodebasicConfog.img_width <= 0 || nodebasicConfog.img_height <= 0) + // { + // return; /* code */ + // } + // InitSheildMask(); + + // printf("regionConfigArr.size() %d \n", regionConfigArr.size()); + // std::sort(regionConfigArr.begin(), regionConfigArr.end(), compareBylay); + // for (int i = 0; i < regionConfigArr.size(); i++) + // { + // printf("mask %d / %d type =%d \n", i, regionConfigArr.size(), regionConfigArr.at(i).basicInfo.type); + // if (regionConfigArr.at(i).basicInfo.type == 1) + // { + // for (int ic = 0; ic < regionConfigArr.at(i).basicInfo.ChannelArry.size(); ic++) + // { + // std::string strChannel = regionConfigArr.at(i).basicInfo.ChannelArry.at(ic); + + // int idx = -1; + // for (int pc = 0; pc < IMG_CHANNEL_Count; pc++) + // { + // if (IMG_CHANNEL_NAME[pc] == strChannel) + // { + // idx = pc; + // } + // } + // printf("%d -- %s idx %d\n", ic, strChannel.c_str(), idx); + // if (idx >= 0) + // { + // if (SheildMask[idx].empty()) + // { + // SheildMask[idx] = cv::Mat(nodebasicConfog.img_height, nodebasicConfog.img_width, CV_8U, cv::Scalar(0)); + // } + // cv::fillPoly(SheildMask[idx], regionConfigArr.at(i).basicInfo.pointArry, cv::Scalar(255)); + + // // cv::imwrite(std::to_string(idx)+"_"+strChannel+".png",SheildMask[idx]); + // } + // } + // } + // } + } + void ToMaskImg() + { + + printf("nodebasicConfog.img_height %d, nodebasicConfog.img_width %d\n", nodebasicConfog.img_height, nodebasicConfog.img_width); + if (nodebasicConfog.img_width <= 0 || nodebasicConfog.img_height <= 0) + { + return; /* code */ + } + + mask = cv::Mat(nodebasicConfog.img_height, nodebasicConfog.img_width, CV_8U, cv::Scalar(0)); + + std::sort(regionConfigArr.begin(), regionConfigArr.end(), compareBylay); + for (int i = 0; i < regionConfigArr.size(); i++) + { + // 只绘制检测区域 + if (regionConfigArr.at(i).basicInfo.type != 0) + { + continue; + } + // printf("*-*-*-*- %d \n", regionConfigArr.at(i).basicInfo.lay); + + int nv = MASK_IMG_STEP * i + MASK_IMG_STARTVALUE; + if (nv < 0 || nv > 255) + { + nv = 255; + } + cv::fillPoly(mask, regionConfigArr.at(i).basicInfo.pointArry, cv::Scalar(nv)); + // { + // std::vector src_pointArry; // 区域点 + // float src_scale_x = SRCIMG_WIDTH * 1.0f / CHECKIMG_WIDTH; + // float src_scale_y = SRCIMG_HEIGHT * 1.0f / CHECKIMG_HEIGHT; + // for (int j = 0; j < regionConfigArr.at(i).basicInfo.pointArry.size(); j++) + // { + // cv::Point temp; + // temp.x = src_scale_x * regionConfigArr.at(i).basicInfo.pointArry.at(j).x; + // temp.y = src_scale_y * regionConfigArr.at(i).basicInfo.pointArry.at(j).y; + // src_pointArry.push_back(temp); + // // printf("--- %d %d **--- %d %d\n",temp.x,temp.y, regionConfigArr.at(i).basicInfo.pointArry.at(j).x, regionConfigArr.at(i).basicInfo.pointArry.at(j).y); + // } + // cv::fillConvexPoly(Src_mask, src_pointArry, cv::Scalar(nv)); + // } + } + } +}; + +// 和图片相关的参数 +struct CommonCheckConfigST +{ + BasicConfig baseConfig; + // 节点参数数据集 + std::vector nodeConfigArr; + CommonCheckConfigST() + { + nodeConfigArr.clear(); + nodeConfigArr.shrink_to_fit(); + } + void copy(CommonCheckConfigST tem) + { + this->nodeConfigArr.assign(tem.nodeConfigArr.begin(), tem.nodeConfigArr.end()); + this->baseConfig.copy(tem.baseConfig); + } +}; +// 基础检测 +struct Function_Base_Det +{ + bool bOpen; // 是否开启 + std::string strAIMode; // 模型名称 + std::vector DetQXList; // 检测缺陷list + + Function_Base_Det() + { + Init(); + } + void Init() + { + bOpen = false; + strAIMode = ""; + + DetQXList.clear(); + DetQXList.shrink_to_fit(); + } + void copy(Function_Base_Det tem) + { + this->bOpen = tem.bOpen; + this->strAIMode = tem.strAIMode; + this->DetQXList.assign(tem.DetQXList.begin(), tem.DetQXList.end()); + } + void print(std::string str) + { + printf("%s>>bOpen %d strAIMode %s ", str.c_str(), bOpen, strAIMode.c_str()); + + for (int i = 0; i < DetQXList.size(); i++) + { + printf("%s ", DetQXList.at(i).c_str()); + } + printf(" \n"); + } + + std::string GetInfo(std::string str) + { + char buffer[128]; + sprintf(buffer, "%s>>bOpen:%d AIMode:%s ", str.c_str(), bOpen, strAIMode.c_str()); + + std::string str123 = buffer; + + for (int i = 0; i < DetQXList.size(); i++) + { + str123 += DetQXList.at(i) + ";"; + } + str123 += "\n"; + return str123; + } +}; +// 检测功能,使用UP画面的缺陷进行过滤 +struct Function_Use_UP_QX +{ + bool bOpen; // 是否开启 + float fIOU; // IOU 值 + Function_Use_UP_QX() + { + Init(); + } + void Init() + { + bOpen = false; + fIOU = 0.80; + } + void copy(Function_Use_UP_QX tem) + { + this->bOpen = tem.bOpen; + this->fIOU = tem.fIOU; + } + void print(std::string str) + { + printf("%s>>bOpen %d, IOU %f \n", str.c_str(), bOpen, fIOU); + } + std::string GetInfo(std::string str) + { + char buffer[64]; + sprintf(buffer, "%s>>bOpen:%d fIOU:%f \n", str.c_str(), bOpen, fIOU); + std::string str123 = buffer; + return str123; + } +}; +// 只生成Blob不进行分析 +struct Function_OnlyBLob +{ + bool bOpen; // 是否开启 + Function_OnlyBLob() + { + Init(); + } + void Init() + { + bOpen = false; + } + void copy(Function_OnlyBLob tem) + { + this->bOpen = tem.bOpen; + } + void print(std::string str) + { + printf("%s>>bOpen %d\n", str.c_str(), bOpen); + } + std::string GetInfo(std::string str) + { + char buffer[64]; + sprintf(buffer, "%s>>bOpen %d\n", str.c_str(), bOpen); + std::string str123 = buffer; + return str123; + } +}; +// 异显检测 +struct Function_YXDet +{ + bool bOpen; // 是否开启 + std::string strModle; + Function_YXDet() + { + Init(); + } + void Init() + { + bOpen = false; + strModle = ""; + } + void copy(Function_YXDet tem) + { + this->bOpen = tem.bOpen; + this->strModle = tem.strModle; + } + void print(std::string str) + { + printf("%s>>bOpen %d strModle %s\n", str.c_str(), bOpen, strModle.c_str()); + } + std::string GetInfo(std::string str) + { + char buffer[64]; + sprintf(buffer, "%s>>bOpen %d strModle %s\n", str.c_str(), bOpen, strModle.c_str()); + std::string str123 = buffer; + return str123; + } +}; +struct Function_AI_QX +{ + bool bOpen; // 是否开启 + bool bPOLToWhitePOL; // 异物转白异物 + bool bAllToChess; // 所有缺陷转Chess + Function_AI_QX() + { + Init(); + } + void Init() + { + bOpen = false; + bPOLToWhitePOL = false; + bAllToChess = false; + } + void copy(Function_AI_QX tem) + { + this->bOpen = tem.bOpen; + this->bPOLToWhitePOL = tem.bPOLToWhitePOL; + this->bAllToChess = tem.bAllToChess; + } + void print(std::string str) + { + printf("%s>>bOpen %d POLToWhitePOL %d AllToChess %d\n", str.c_str(), bOpen, bPOLToWhitePOL, bAllToChess); + } + std::string GetInfo(std::string str) + { + char buffer[64]; + sprintf(buffer, "%s>>bOpen %d POLToWhitePOL %d AllToChess %d\n", str.c_str(), bOpen, bPOLToWhitePOL, bAllToChess); + std::string str123 = buffer; + return str123; + } +}; +// 亮点 +struct Function_AI_LD +{ + bool bOpen; // 是否开启 + bool bUseDP; // 是否使用DP检测结果 + bool bWTBLD; // 是否是WTB亮点 + bool bHSLD; // 黑闪类型的亮点 + float fDP_IOU; // DP的IOU + Function_AI_LD() + { + Init(); + } + void Init() + { + bOpen = false; + bUseDP = false; + bWTBLD = false; + bHSLD = false; + fDP_IOU = 0.1; + } + void copy(Function_AI_LD tem) + { + this->bOpen = tem.bOpen; + this->bUseDP = tem.bUseDP; + this->bWTBLD = tem.bWTBLD; + this->bHSLD = tem.bHSLD; + this->fDP_IOU = tem.fDP_IOU; + } + void print(std::string str) + { + printf("%s>>bOpen %d bUseDP %d bWTBLD %d bHSLD %d fDP_IOU %f\n", str.c_str(), bOpen, bUseDP, bWTBLD, bHSLD, fDP_IOU); + } + std::string GetInfo(std::string str) + { + char buffer[64]; + sprintf(buffer, "%s>>bOpen %d bUseDP %d bWTBLD %d bHSLD %d fDP_IOU %f\n", str.c_str(), bOpen, bUseDP, bWTBLD, bHSLD, fDP_IOU); + std::string str123 = buffer; + return str123; + } +}; + +// 大缺陷检测参数 +struct Function_BigQX +{ + bool bOpen; // 是否开启 + float Single_Area; // 单个缺陷的面积 + int Single_HJ; // 单个缺陷的灰机 + float Single_Len; // 单个缺陷的长度 + int Sum_blob_Num; // 总面积统计 blob数量 + float Sum_Area; // 总面积统计 面积参数 + Function_BigQX() + { + Init(); + } + void Init() + { + bOpen = false; + Single_Area = 80; + Single_HJ = 60; + Single_Len = 5; + Sum_blob_Num = 5; + Sum_Area = 100; + } + void copy(Function_BigQX tem) + { + this->bOpen = tem.bOpen; + this->Single_Area = tem.Single_Area; + this->Single_HJ = tem.Single_HJ; + this->Single_Len = tem.Single_Len; + this->Sum_blob_Num = tem.Sum_blob_Num; + this->Sum_Area = tem.Sum_Area; + } + void print(std::string str) + { + printf("%s>>bOpen %d single area %f hj %d len %f sum blob num %d area %f\n", str.c_str(), + bOpen, Single_Area, Single_HJ, Single_Len, Sum_blob_Num, Sum_Area); + } + std::string GetInfo(std::string str) + { + char buffer[128]; + sprintf(buffer, "%s>>bOpen %d single area %f hj %d len %f sum blob num %d area %f\n", str.c_str(), + bOpen, Single_Area, Single_HJ, Single_Len, Sum_blob_Num, Sum_Area); + std::string str123 = buffer; + return str123; + } +}; + +// 屏蔽区域参数 +struct Function_ShieldRegion +{ + bool bOpen; // 是否开启 + + bool bDraw; // 是否绘制 + cv::Mat shieldMask; // 屏蔽区域图片 + std::vector pointArry1; // 区域点 + std::vector pointArry2; // 区域点 + std::vector pointArry3; // 区域点 + std::vector pointArry4; // 区域点 + std::vector pointArry5; // 区域点 + Function_ShieldRegion() + { + Init(); + } + void Init() + { + bOpen = false; + bDraw = true; + + pointArry1.clear(); + pointArry1.shrink_to_fit(); + + pointArry2.clear(); + pointArry2.shrink_to_fit(); + + pointArry3.clear(); + pointArry3.shrink_to_fit(); + + pointArry4.clear(); + pointArry4.shrink_to_fit(); + + pointArry5.clear(); + pointArry5.shrink_to_fit(); + if (!shieldMask.empty()) + { + shieldMask.release(); + } + } + + void copy(Function_ShieldRegion tem) + { + this->bOpen = tem.bOpen; + this->bDraw = tem.bDraw; + this->shieldMask = tem.shieldMask.clone(); + this->pointArry1.assign(tem.pointArry1.begin(), tem.pointArry1.end()); + this->pointArry2.assign(tem.pointArry2.begin(), tem.pointArry2.end()); + this->pointArry3.assign(tem.pointArry3.begin(), tem.pointArry3.end()); + this->pointArry4.assign(tem.pointArry4.begin(), tem.pointArry4.end()); + this->pointArry5.assign(tem.pointArry5.begin(), tem.pointArry5.end()); + } + void ToMaskImg(int img_W, int img_H) + { + if (img_W > 0 && img_H > 0) + { + if (!shieldMask.empty()) + { + shieldMask.release(); + } + + if (!bOpen) + { + return; + } + shieldMask = cv::Mat(img_H, img_W, CV_8U, cv::Scalar(0)); + if (pointArry1.size() > 0) + { + cv::fillPoly(shieldMask, pointArry1, cv::Scalar(255)); + } + if (pointArry2.size() > 0) + { + cv::fillPoly(shieldMask, pointArry2, cv::Scalar(255)); + } + if (pointArry3.size() > 0) + { + cv::fillPoly(shieldMask, pointArry3, cv::Scalar(255)); + } + if (pointArry4.size() > 0) + { + cv::fillPoly(shieldMask, pointArry4, cv::Scalar(255)); + } + if (pointArry5.size() > 0) + { + cv::fillPoly(shieldMask, pointArry5, cv::Scalar(255)); + } + } + } + void print(std::string str) + { + printf("%s>>bOpen %d bDraw %d maskimg empty %d\n", str.c_str(), + bOpen, bDraw, shieldMask.empty()); + } + std::string GetInfo(std::string str) + { + char buffer[128]; + sprintf(buffer, "%s>>bOpen %d bDraw %d maskimg empty %d\n", str.c_str(), + bOpen, bDraw, shieldMask.empty()); + std::string str123 = buffer; + return str123; + } +}; +// 启用127cell 独立检测 +struct Function_Det_127_Cell +{ + bool bOpen; // 是否开启 + Function_Det_127_Cell() + { + Init(); + } + void Init() + { + bOpen = false; + } + void copy(Function_Det_127_Cell tem) + { + this->bOpen = tem.bOpen; + } + void print(std::string str) + { + printf("%s>>bOpen %d \n", str.c_str(), bOpen); + } + std::string GetInfo(std::string str) + { + char buffer[64]; + sprintf(buffer, "%s>>bOpen %d\n", str.c_str(), bOpen); + std::string str123 = buffer; + return str123; + } +}; + +// 检测roi区域参数 +struct Function_EdgeROI +{ + bool bOpen; // 是否开启 + bool Use_DrawROI; // 使用绘制ROI + bool Use_DetEdge; // 使用边缘检测 + bool Use_AIEdge; // 使用AI检测 + bool AI_Fail_UseDraw; // 如果AI 失败使用绘制; + int threshold_value; // 二值化值 + int AI_Erode_Size; // AI 检测 腐蚀的半径。 + cv::Mat EdgeMask; // 边缘区域图片 + std::vector pointArry1; // 区域点 + Function_EdgeROI() + { + Init(); + } + void Init() + { + bOpen = false; + Use_DrawROI = false; + Use_DetEdge = true; + Use_AIEdge = false; + AI_Fail_UseDraw = false; + threshold_value = 11; + AI_Erode_Size = 7; + pointArry1.clear(); + pointArry1.shrink_to_fit(); + if (!EdgeMask.empty()) + { + EdgeMask.release(); + } + } + + void copy(Function_EdgeROI tem) + { + this->bOpen = tem.bOpen; + this->Use_DrawROI = tem.Use_DrawROI; + this->Use_DetEdge = tem.Use_DetEdge; + this->Use_AIEdge = tem.Use_AIEdge; + this->AI_Fail_UseDraw = tem.AI_Fail_UseDraw; + this->threshold_value = tem.threshold_value; + this->AI_Erode_Size = tem.AI_Erode_Size; + this->EdgeMask = tem.EdgeMask.clone(); + this->pointArry1.assign(tem.pointArry1.begin(), tem.pointArry1.end()); + } + void ToMaskImg(int img_W, int img_H) + { + if (img_W > 0 && img_H > 0) + { + if (!EdgeMask.empty()) + { + EdgeMask.release(); + } + if (!bOpen) + { + return; + } + // if (!Use_DrawROI) + // { + // return; + // } + EdgeMask = cv::Mat(img_H, img_W, CV_8U, cv::Scalar(0)); + + if (pointArry1.size() > 0) + { + cv::fillPoly(EdgeMask, pointArry1, cv::Scalar(255)); + } + else + { + printf("pointArry1 == 0 \n\n\n"); + } + } + } + void print(std::string str) + { + printf("%s>>bOpen %d Use_DrawROI %d Use_DetEdge %d Use_AIEdge %d AI_Fail_UseDraw %d threshold_value %d AI_Erode_Size %d EdgeMask empty %d\n", str.c_str(), + bOpen, Use_DrawROI, Use_DetEdge, Use_AIEdge, AI_Fail_UseDraw, threshold_value, AI_Erode_Size, EdgeMask.empty()); + } + std::string GetInfo(std::string str) + { + char buffer[256]; + sprintf(buffer, "%s>>bOpen %d Use_DrawROI %d Use_DetEdge %d Use_AIEdge %d AI_Fail_UseDraw %d threshold_value %d AI_Erode_Size %d EdgeMask empty %d\n", str.c_str(), + bOpen, Use_DrawROI, Use_DetEdge, Use_AIEdge, AI_Fail_UseDraw, threshold_value, AI_Erode_Size, EdgeMask.empty()); + std::string str123 = buffer; + return str123; + } +}; + +// 图片对齐功能 +struct Function_Image_Align +{ + enum RunType + { + type_Use, // 使用 + type_Test, // 仅测试 + }; + bool bOpen; // 是否开启 + bool bDraw; // 是否绘制 + float fscore; // 定位分数 + RunType runType; // 运行模式 + cv::Rect search_Roi; // 搜索区域 + cv::Rect feature_Roi; // 特征区域 + cv::Mat feature_Mask; // 特征mask + cv::Rect Crop_Roi; // 产品裁切区域 + std::vector pointArry1; // 特征区域点 + Function_Image_Align() + { + Init(); + } + void Init() + { + bOpen = false; + bDraw = false; + fscore = 0.9; + search_Roi = cv::Rect(0, 0, 0, 0); + feature_Roi = cv::Rect(0, 0, 0, 0); + Crop_Roi = cv::Rect(0, 0, 0, 0); + pointArry1.clear(); + pointArry1.shrink_to_fit(); + if (!feature_Mask.empty()) + { + feature_Mask.release(); + } + runType = type_Use; + } + // 将枚举值转换为字符串 + std::string colorToString(RunType c) + { + switch (c) + { + case type_Use: + return "Use"; + case type_Test: + return "Test"; + default: + return "Use"; + } + } + void copy(Function_Image_Align tem) + { + this->bOpen = tem.bOpen; + this->bDraw = tem.bDraw; + this->fscore = tem.fscore; + this->search_Roi = tem.search_Roi; + this->feature_Roi = tem.feature_Roi; + this->Crop_Roi = tem.Crop_Roi; + this->feature_Mask = tem.feature_Mask.clone(); + this->pointArry1.assign(tem.pointArry1.begin(), tem.pointArry1.end()); + this->runType = tem.runType; + } + void ToMaskImg(int img_W, int img_H) + { + if (img_W > 0 && img_H > 0) + { + if (!feature_Mask.empty()) + { + feature_Mask.release(); + } + if (!bOpen) + { + return; + } + // cv::Rect boundingRect = cv::boundingRect(pointArry1); + // feature_Roi = boundingRect; + // for (int i = 0; i < pointArry1.size(); i++) + // { + // pointArry1[i].x -= boundingRect.x; + // pointArry1[i].y -= boundingRect.y; + // } + + cv::Mat tem_feature_Mask = cv::Mat(img_H, img_W, CV_8U, cv::Scalar(0)); + + if (pointArry1.size() > 0) + { + cv::fillPoly(tem_feature_Mask, pointArry1, cv::Scalar(255)); + } + else + { + printf("pointArry1 == 0 \n\n\n"); + } + feature_Mask = tem_feature_Mask(feature_Roi).clone(); + } + } + void print(std::string str) + { + printf("%s>>bOpen %d bDraw %d fscore %f feature_Mask empty %d run type = %s\n", str.c_str(), + bOpen, bDraw, fscore, feature_Mask.empty(), colorToString(runType).c_str()); + } + std::string GetInfo(std::string str) + { + char buffer[128]; + sprintf(buffer, "%s>>bOpen %d bDraw %d fscore %f feature_Mask empty %d run type = %s\n", str.c_str(), + bOpen, bDraw, fscore, feature_Mask.empty(), colorToString(runType).c_str()); + std::string str123 = buffer; + return str123; + } +}; + +// 缺失Pol检测 +struct Function_Detect_LackPol +{ + + bool bOpen; // 是否开启 + + Function_Detect_LackPol() + { + Init(); + } + void Init() + { + bOpen = false; + } + + void copy(Function_Detect_LackPol tem) + { + this->bOpen = tem.bOpen; + } + void print(std::string str) + { + printf("%s>>bOpen %d \n", str.c_str(), + bOpen); + } + std::string GetInfo(std::string str) + { + char buffer[128]; + sprintf(buffer, "%s>>bOpen %d\n", str.c_str(), + bOpen); + std::string str123 = buffer; + return str123; + } +}; + +// 二次精确检测 +struct Function_SecondDet +{ + + bool bOpen; // 是否开启 + + bool andian_Open_area; // 暗点 开启面积检测 + bool andian_Open_len; // 暗点 开启长度检测 + float andian_area_min; // 暗点 面积范围 + float andian_area_max; // 暗点 面积范围 + bool andian_saveProcessImg; // 暗点 存储图片 + + bool pol_Open_area; // pol 开启面积检测 + bool pol_Open_len; // pol 开启长度检测 + float pol_area_min; // pol 面积范围 + float pol_area_max; // pol 面积范围 + bool pol_open_SingleCheck; // pol 开启独立参数分析 + bool pol_open_Create; // pol 可以生成新异物 + bool pol_saveProcessImg; // pol 存储图片 + + Function_SecondDet() + { + Init(); + } + void Init() + { + bOpen = false; + andian_Open_area = false; + andian_Open_len = false; + andian_area_min = 0; + andian_area_max = 0.25; + andian_saveProcessImg = false; + + pol_Open_area = false; + pol_Open_len = false; + pol_area_min = 0; + pol_area_max = 0.25; + pol_open_SingleCheck = false; + pol_open_Create = false; + pol_saveProcessImg = false; + } + + void copy(Function_SecondDet tem) + { + this->bOpen = tem.bOpen; + + this->andian_Open_area = tem.andian_Open_area; + this->andian_Open_len = tem.andian_Open_len; + this->andian_area_min = tem.andian_area_min; + this->andian_area_max = tem.andian_area_max; + this->andian_saveProcessImg = tem.andian_saveProcessImg; + + this->pol_Open_area = tem.pol_Open_area; + this->pol_Open_len = tem.pol_Open_len; + this->pol_area_min = tem.pol_area_min; + this->pol_area_max = tem.pol_area_max; + this->pol_open_SingleCheck = tem.pol_open_SingleCheck; + this->pol_open_Create = tem.pol_open_Create; + this->pol_saveProcessImg = tem.pol_saveProcessImg; + } + void print(std::string str) + { + printf("%s>>bOpen %d andian : Open_area %d Open_len %d bsaveimg %d area_minmax %f-%f\n", str.c_str(), + bOpen, andian_Open_area, andian_Open_len, andian_saveProcessImg, andian_area_min, andian_area_max); + printf("%s>>bOpen %d pol : Open_area %d Open_len %d bsaveimg %d area_minmax %f-%f singlecheck %d create %d\n", str.c_str(), + bOpen, pol_Open_area, pol_Open_len, pol_saveProcessImg, pol_area_min, pol_area_max, pol_open_SingleCheck, pol_open_Create); + } + std::string GetInfo(std::string str) + { + char buffer[256]; + sprintf(buffer, "%s>>bOpen %d andian : Open_area %d Open_len %d bsaveimg %d area_minmax %f-%f pol : Open_area %d Open_len %d bsaveimg %d area_minmax %f-%f singlecheck %d create %d\n", str.c_str(), + bOpen, andian_Open_area, andian_Open_len, andian_saveProcessImg, andian_area_min, andian_area_max, + pol_Open_area, pol_Open_len, pol_saveProcessImg, pol_area_min, pol_area_max, pol_open_SingleCheck, pol_open_Create); + std::string str123 = buffer; + return str123; + } +}; +// 暗点的 S标准 +struct AD_S_Standard +{ + float area; // 面积 + float len; // 长度 + AD_S_Standard() + { + Init(); + } + void Init() + { + area = 0; + len = 0; + } + void copy(AD_S_Standard tem) + { + this->area = tem.area; + this->len = tem.len; + } + std::string GetInfo(std::string str) + { + char buffer[256]; + sprintf(buffer, "%s:area %f len %f;", str.c_str(), + area, len); + std::string str123 = buffer; + return str123; + } +}; +// 暗点数量分析 +struct AD_Analysisy_Num +{ + bool bOpen; // 是否开启 + int numT; // 数量阈值 + AD_Analysisy_Num() + { + Init(); + } + void Init() + { + bOpen = false; + numT = 0; + } + void copy(AD_Analysisy_Num tem) + { + this->bOpen = tem.bOpen; + this->numT = tem.numT; + } + std::string GetInfo(std::string str) + { + char buffer[256]; + sprintf(buffer, "%s:bOpen %d num %d;", str.c_str(), + bOpen, numT); + std::string str123 = buffer; + return str123; + } +}; +// 暗点距离分析 +struct AD_Analysisy_Dis +{ + bool bOpen; // 是否开启 + float disT; // 距离阈值 + AD_Analysisy_Dis() + { + Init(); + } + void Init() + { + bOpen = false; + disT = 0; + } + void copy(AD_Analysisy_Dis tem) + { + this->bOpen = tem.bOpen; + this->disT = tem.disT; + } + std::string GetInfo(std::string str) + { + char buffer[256]; + sprintf(buffer, "%s:bOpen %d dis %f;", str.c_str(), + bOpen, disT); + std::string str123 = buffer; + return str123; + } +}; + +// 暗点S标准分析 +struct AD_Analysisy_S +{ + bool bOpen; // 是否开启 + bool NG_3s; // 直接NG 的 3S 值。 + int Check_s_Value; // 有数量数量要求的s值。 + int Check_s_Num; // 数量要求。 + AD_Analysisy_S() + { + Init(); + } + void Init() + { + bOpen = false; + NG_3s = false; + Check_s_Value = 2; + Check_s_Num = 2; + } + void copy(AD_Analysisy_S tem) + { + this->bOpen = tem.bOpen; + this->NG_3s = tem.NG_3s; + this->Check_s_Value = tem.Check_s_Value; + this->Check_s_Num = tem.Check_s_Num; + } + std::string GetInfo(std::string str) + { + char buffer[256]; + sprintf(buffer, "%s:bOpen %d s_Value %d s_Num %d NG_3s %d;", str.c_str(), + bOpen, Check_s_Value, Check_s_Num, NG_3s); + std::string str123 = buffer; + return str123; + } +}; +// 暗点检测功能 +struct Function_AD_Check +{ + + bool bOpen; // 是否开启 + AD_S_Standard S_standard_3s; // 3s 标准 + AD_S_Standard S_standard_2s; // 2s 标准 + AD_S_Standard S_standard_1s; // 1s 标准 + AD_Analysisy_Num analysis_num; // 数量分析 + AD_Analysisy_Dis analysis_dis; // 距离分析 + AD_Analysisy_S analysis_s; // s 标准分析 + + Function_AD_Check() + { + Init(); + } + void Init() + { + bOpen = false; + S_standard_3s.Init(); + S_standard_2s.Init(); + S_standard_1s.Init(); + analysis_num.Init(); + analysis_dis.Init(); + analysis_s.Init(); + } + + void copy(Function_AD_Check tem) + { + this->bOpen = tem.bOpen; + this->S_standard_3s.copy(tem.S_standard_3s); + this->S_standard_2s.copy(tem.S_standard_2s); + this->S_standard_1s.copy(tem.S_standard_1s); + this->analysis_num.copy(tem.analysis_num); + this->analysis_dis.copy(tem.analysis_dis); + this->analysis_s.copy(tem.analysis_s); + } + void print(std::string str) + { + printf("%s>>bOpen %d %s %s %s %s %s %s\n", str.c_str(), + bOpen, S_standard_3s.GetInfo("3S").c_str(), + S_standard_2s.GetInfo("2S").c_str(), + S_standard_1s.GetInfo("1S").c_str(), + analysis_num.GetInfo("analysis_num").c_str(), + analysis_dis.GetInfo("analysis_dis").c_str(), + analysis_s.GetInfo("analysis_s").c_str()); + } + std::string GetInfo(std::string str) + { + char buffer[256]; + sprintf(buffer, "%s>>bOpen %d ", str.c_str(), bOpen); + std::string str123 = buffer; + str123 += S_standard_3s.GetInfo("3S"); + str123 += S_standard_2s.GetInfo("2S"); + str123 += S_standard_1s.GetInfo("1S"); + str123 += analysis_num.GetInfo("analysis_num"); + str123 += analysis_dis.GetInfo("analysis_dis"); + str123 += analysis_s.GetInfo("analysis_s"); + + return str123; + } +}; + +// 异物检测功能 +struct Function_POL_Check +{ + + bool bOpen; // 是否开启 + int numT; // 数量阈值 + Function_POL_Check() + { + Init(); + } + void Init() + { + bOpen = false; + numT = 0; + } + + void copy(Function_POL_Check tem) + { + this->bOpen = tem.bOpen; + this->numT = tem.numT; + } + void print(std::string str) + { + printf("%s>>bOpen %d %d\n", str.c_str(), + bOpen, + numT); + } + std::string GetInfo(std::string str) + { + char buffer[256]; + sprintf(buffer, "%s>>bOpen %d num %d", str.c_str(), bOpen, numT); + std::string str123 = buffer; + + return str123; + } +}; +// 检测功能 +struct CheckFunction +{ + Function_Base_Det f_BaseDet; // 基础检测 + Function_Use_UP_QX f_UseUpQX; // 使用UP画面的缺陷进行过滤 + Function_OnlyBLob f_OnlyBLob; // 只获取blob ,不进行分析 + Function_YXDet f_YXDet; // 异显检测 + Function_AI_QX f_AIQX; // 缺陷分类设置 + Function_AI_LD f_LDConfig; // 亮点参数 + Function_BigQX f_Big_QX; + Function_ShieldRegion f_ShieldRegion; + Function_Det_127_Cell f_Det127Cell; + Function_EdgeROI f_EdgeROI; + Function_Image_Align f_Image_Align; // 图片特征对齐 + Function_Detect_LackPol f_Dectect_LackPol; // 缺失POL检测 + Function_SecondDet f_SecondDetect; // 二次检测分析 + Function_AD_Check f_AD_Check; // 暗点的检测功能 + Function_POL_Check f_POL_Check; // 异物的检测功能 + CheckFunction() + { + Init(); + } + void Init() + { + f_UseUpQX.Init(); + f_BaseDet.Init(); + f_OnlyBLob.Init(); + f_YXDet.Init(); + f_AIQX.Init(); + f_LDConfig.Init(); + f_Big_QX.Init(); + f_ShieldRegion.Init(); + f_Det127Cell.Init(); + f_EdgeROI.Init(); + f_Image_Align.Init(); + f_Dectect_LackPol.Init(); + f_SecondDetect.Init(); + f_AD_Check.Init(); + f_POL_Check.Init(); + } + void copy(CheckFunction tem) + { + + this->f_UseUpQX.copy(tem.f_UseUpQX); + this->f_BaseDet.copy(tem.f_BaseDet); + this->f_OnlyBLob.copy(tem.f_OnlyBLob); + this->f_YXDet.copy(tem.f_YXDet); + this->f_AIQX.copy(tem.f_AIQX); + this->f_LDConfig.copy(tem.f_LDConfig); + this->f_Big_QX.copy(tem.f_Big_QX); + this->f_ShieldRegion.copy(tem.f_ShieldRegion); + this->f_Det127Cell.copy(tem.f_Det127Cell); + this->f_EdgeROI.copy(tem.f_EdgeROI); + this->f_Image_Align.copy(tem.f_Image_Align); + this->f_Dectect_LackPol.copy(tem.f_Dectect_LackPol); + this->f_SecondDetect.copy(tem.f_SecondDetect); + this->f_AD_Check.copy(tem.f_AD_Check); + this->f_POL_Check.copy(tem.f_POL_Check); + } + void print(std::string str) + { + printf("%s>>\n", str.c_str()); + f_BaseDet.print("BaseDet"); + f_UseUpQX.print("UseUpQX"); + f_OnlyBLob.print("OnlyBLob"); + f_YXDet.print("YXDet"); + f_AIQX.print("AIQX"); + f_LDConfig.print("LDConfig"); + f_Big_QX.print("Big_QX"); + f_ShieldRegion.print("ShieldRegion"); + f_Det127Cell.print("Det127Cell"); + f_EdgeROI.print("EdgeROI"); + f_Image_Align.print("Image_Align"); + f_Dectect_LackPol.print("Dectect_LackPol"); + f_SecondDetect.print("SecondDetect"); + f_AD_Check.print("f_AD_Check"); + f_POL_Check.print("f_POL_Check"); + } + std::string GetInfo(std::string str) + { + + std::string str123 = str + ":\n"; + str123 += f_BaseDet.GetInfo("BaseDet"); + str123 += f_UseUpQX.GetInfo("UseUpQX"); + str123 += f_OnlyBLob.GetInfo("f_OnlyBLob"); + str123 += f_YXDet.GetInfo("YXDet"); + str123 += f_AIQX.GetInfo("AIQX"); + str123 += f_LDConfig.GetInfo("LDConfig"); + str123 += f_Big_QX.GetInfo("Big_QX"); + str123 += f_ShieldRegion.GetInfo("ShieldRegion"); + str123 += f_Det127Cell.GetInfo("Det127Cell"); + str123 += f_EdgeROI.GetInfo("EdgeROI"); + str123 += f_Image_Align.GetInfo("Image_Align"); + str123 += f_Dectect_LackPol.GetInfo("Dectect_LackPol"); + str123 += f_SecondDetect.GetInfo("SecondDetect"); + str123 += f_AD_Check.GetInfo("f_AD_Check"); + str123 += f_AD_Check.GetInfo("f_POL_Check"); + return str123; + } +}; +// 单通道检测功能 +struct ChannelCheckFunction +{ + std::string strChannelName; + CheckFunction function; // 使用UP画面的缺陷进行过滤 + ChannelCheckFunction() + { + Init(); + } + void Init() + { + strChannelName = ""; + function.Init(); + } + void copy(ChannelCheckFunction tem) + { + this->strChannelName = tem.strChannelName; + this->function.copy(tem.function); + } + void print(std::string str) + { + printf("%s>> %s\n", str.c_str(), strChannelName.c_str()); + function.print("function"); + } + std::string GetInfo(std::string str) + { + std::string str123 = ""; + str123 += strChannelName + ":\n"; + str123 += function.GetInfo("function"); + // str123 += "\n"; + + return str123; + } +}; + +// 基础检测功能 mark +struct Base_Function_MarkLine +{ + + bool bOpen; // 是否开启 + bool bDraw; // 是否绘制 + bool badapt_region; // 是否自适应区域 + cv::Rect productROI; + std::vector region; + cv::Point mark_local_1; + cv::Point mark_local_2; + + Base_Function_MarkLine() + { + Init(); + } + void Init() + { + bOpen = false; + bDraw = false; + badapt_region = false; + mark_local_1 = cv::Point(0, 0); + mark_local_2 = cv::Point(0, 0); + productROI = cv::Rect(0, 0, 0, 0); + region.clear(); + } + + void copy(Base_Function_MarkLine tem) + { + this->bOpen = tem.bOpen; + this->region.assign(tem.region.begin(), tem.region.end()); + this->productROI = tem.productROI; + this->bDraw = tem.bDraw; + this->badapt_region = tem.badapt_region; + this->mark_local_1 = tem.mark_local_1; + this->mark_local_2 = tem.mark_local_2; + } + void print(std::string str) + { + printf("%s>>bOpen %d bDraw %d badapt_region %d mark1 [%d %d] mark2 [%d %d] \n", str.c_str(), + bOpen, bDraw, badapt_region,mark_local_1.x, mark_local_1.y, mark_local_2.x, mark_local_2.y); + } + std::string GetInfo(std::string str) + { + char buffer[256]; + sprintf(buffer, "%s>>bOpen %d bDraw %d badapt_region %d mark1 [%d %d] mark2 [%d %d] \n", str.c_str(), + bOpen, bDraw, badapt_region,mark_local_1.x, mark_local_1.y, mark_local_2.x, mark_local_2.y); + std::string str123 = buffer; + return str123; + } +}; + +// 基础检测功能 存图设置 +struct Base_Function_SaveImg +{ + + bool bOpen; // 是否开启 + bool bSaveMarkImg; // mark 存图 + bool bSaveClsImg; // 分类 存图 + bool bSaveAlginImg; // 分类 存图 + + Base_Function_SaveImg() + { + Init(); + } + void Init() + { + bOpen = false; + bSaveMarkImg = false; + bSaveClsImg = false; + bSaveAlginImg = false; + } + + void copy(Base_Function_SaveImg tem) + { + this->bOpen = tem.bOpen; + + this->bSaveMarkImg = tem.bSaveMarkImg; + this->bSaveClsImg = tem.bSaveClsImg; + this->bSaveAlginImg = tem.bSaveAlginImg; + } + void print(std::string str) + { + printf("%s>>bOpen %d bSaveMarkImg %d bSaveClsImg %d bSaveAlginImg %d \n", str.c_str(), + bOpen, bSaveMarkImg, bSaveClsImg, bSaveAlginImg); + } + std::string GetInfo(std::string str) + { + char buffer[256]; + sprintf(buffer, "%s>>bOpen %d bSaveMarkImg %d bSaveClsImg %d bSaveAlginImg %d \n", str.c_str(), + bOpen, bSaveMarkImg, bSaveClsImg, bSaveAlginImg); + std::string str123 = buffer; + return str123; + } +}; + +// 大缺陷 NG +struct Big_NG +{ + + bool bOpen; // 是否开启 + float fArea; + std::string strname; + + Big_NG() + { + Init(); + } + void Init() + { + bOpen = false; + fArea = 1; + strname = ""; + } + + void copy(Big_NG tem) + { + this->bOpen = tem.bOpen; + this->fArea = tem.fArea; + this->strname = tem.strname; + } + void print(std::string str) + { + printf("%s>>bOpen %d strname %s fArea %f \n", str.c_str(), + bOpen, strname.c_str(), fArea); + } + std::string GetInfo(std::string str) + { + char buffer[256]; + sprintf(buffer, "%s>>bOpen %d strname %s fArea %f \n", str.c_str(), + bOpen, strname.c_str(), fArea); + std::string str123 = buffer; + return str123; + } +}; +// 基础检测功能 大缺陷 NG +struct Base_Function_BigNG +{ + + bool bOpen; // 是否开启 + bool usPreResult; + Big_NG qx[CONFIG_QX_NAME_count]; + + Base_Function_BigNG() + { + Init(); + } + void Init() + { + bOpen = false; + usPreResult = true; + for (int i = 0; i < CONFIG_QX_NAME_count; i++) + { + qx[i].Init(); + } + } + + void copy(Base_Function_BigNG tem) + { + this->bOpen = tem.bOpen; + + for (int i = 0; i < CONFIG_QX_NAME_count; i++) + { + this->qx[i].copy(tem.qx[i]); + } + } + void print(std::string str) + { + printf("%s>>bOpen %d \n", str.c_str(), + bOpen); + for (int i = 0; i < CONFIG_QX_NAME_count; i++) + { + printf("%s \n", qx[i].GetInfo("").c_str()); + } + } + std::string GetInfo(std::string str) + { + char buffer[256]; + sprintf(buffer, "%s>>bOpen %d \n", str.c_str(), + bOpen); + std::string str123 = buffer; + for (int i = 0; i < CONFIG_QX_NAME_count; i++) + { + str123 += qx[i].GetInfo(""); + } + return str123; + } +}; +// 基础检测功能 CELL AOI 边缘缺陷检测 +struct Base_Function_Edge_Det +{ + + bool bOpen; // 是否开启 + int Search_threshold; // 搜索边缘阈值 + int Det_threshold; // 缺陷检测阈值 + int Det_Range; // 检测范围 + int QX_Widht_min; // 缺陷宽度-最小 + int QX_Widht_max; + int QX_Height_min; + int QX_Height_max; + + bool queJiao_LU_Open; + bool queJiao_RU_Open; + bool queJiao_LD_Open; + bool queJiao_RD_Open; + int queJiao_width; + int queJiao_height; + + bool bDrawRoi; + cv::Rect draw_ROI; + std::vector region; + + bool bDrawResult; // 是否绘制结果 + Base_Function_Edge_Det() + { + Init(); + } + void Init() + { + bOpen = false; + Search_threshold = 30; + Det_threshold = 30; + Det_Range = 100; + QX_Widht_min = 10; + QX_Widht_max = 100; + QX_Height_min = 10; + QX_Height_max = 100; + + queJiao_LU_Open = false; + queJiao_RU_Open = false; + queJiao_LD_Open = false; + queJiao_RD_Open = false; + queJiao_width = 50; + queJiao_height = 50; + bDrawRoi = false; + draw_ROI = cv::Rect(0, 0, 0, 0); + region.clear(); + region.erase(region.begin(), region.end()); + bDrawResult = false; + } + + void copy(Base_Function_Edge_Det tem) + { + this->bOpen = tem.bOpen; + this->Search_threshold = tem.Search_threshold; + this->Det_threshold = tem.Det_threshold; + this->Det_Range = tem.Det_Range; + this->QX_Widht_min = tem.QX_Widht_min; + this->QX_Widht_max = tem.QX_Widht_max; + this->QX_Height_min = tem.QX_Height_min; + this->QX_Height_max = tem.QX_Height_max; + + this->queJiao_LU_Open = tem.queJiao_LU_Open; + this->queJiao_RU_Open = tem.queJiao_RU_Open; + this->queJiao_LD_Open = tem.queJiao_LD_Open; + this->queJiao_RD_Open = tem.queJiao_RD_Open; + this->queJiao_width = tem.queJiao_width; + this->queJiao_height = tem.queJiao_height; + + this->region.assign(tem.region.begin(), tem.region.end()); + this->draw_ROI = tem.draw_ROI; + this->bDrawRoi = tem.bDrawRoi; + this->bDrawResult = tem.bDrawResult; + } + void print(std::string str) + { + printf("%s>>bOpen %d Search_threshold %d Det_threshold %d Det_Range %d QX_Widht [%d %d] QX_Height [%d %d]\n", str.c_str(), + bOpen, Search_threshold, Det_threshold, Det_Range, QX_Widht_min, QX_Widht_max, QX_Height_min, QX_Height_max); + } + std::string GetInfo(std::string str) + { + char buffer[256]; + sprintf(buffer, "%s>>bOpen %d Search_threshold %d Det_threshold %d Det_Range %d QX_Widht [%d %d] QX_Height [%d %d]\n", str.c_str(), + bOpen, Search_threshold, Det_threshold, Det_Range, QX_Widht_min, QX_Widht_max, QX_Height_min, QX_Height_max); + std::string str123 = buffer; + return str123; + } +}; +// 基础检测功能 +struct BaseCheckFunction +{ + Base_Function_MarkLine markLine; + Base_Function_Edge_Det edgeDet; + Base_Function_SaveImg saveImg; + Base_Function_BigNG bigNG; + BaseCheckFunction() + { + Init(); + } + void Init() + { + markLine.Init(); + edgeDet.Init(); + saveImg.Init(); + bigNG.Init(); + } + void copy(BaseCheckFunction tem) + { + this->markLine.copy(tem.markLine); + this->edgeDet.copy(tem.edgeDet); + this->saveImg.copy(tem.saveImg); + this->bigNG.copy(tem.bigNG); + } + void print(std::string str) + { + printf("******* %s *********\n", str.c_str()); + markLine.print("markLine"); + edgeDet.print("edgeDet"); + saveImg.print("saveImg"); + bigNG.print("bigNG"); + } + std::string GetInfo(std::string str) + { + std::string str123 = ""; + str123 += markLine.GetInfo("markLine"); + str123 += edgeDet.GetInfo("edgeDet"); + str123 += saveImg.GetInfo("saveImg"); + str123 += bigNG.GetInfo("bigNG"); + // str123 += "\n"; + return str123; + } +}; +// 所有通道检测功能 +struct ALLChannelCheckFunction +{ + std::vector channelFunctionArr; // 所有通道的参数。 + ALLChannelCheckFunction() + { + Init(); + } + void Init() + { + channelFunctionArr.clear(); + channelFunctionArr.shrink_to_fit(); + } + void copy(ALLChannelCheckFunction tem) + { + this->channelFunctionArr.assign(tem.channelFunctionArr.begin(), tem.channelFunctionArr.end()); + } + void print(std::string str) + { + printf("%s===========================\n", str.c_str()); + for (int i = 0; i < channelFunctionArr.size(); i++) + { + channelFunctionArr.at(i).print(""); + } + printf("%s===========================\n", str.c_str()); + } +}; + +// 和相机相关的分析参数 +struct AnalysisyConfigST +{ + std::string strSkuName; + CommonCheckConfigST commonCheckConfig; // 和图片相关的参数 + + ALLChannelCheckFunction checkFunction; // 每个通道的检测功能 + + BaseCheckFunction baseFunction; // 检测检测的function + AnalysisyConfigST() + { + strSkuName = ""; + } + void copy(AnalysisyConfigST tem) + { + this->strSkuName = tem.strSkuName; + this->commonCheckConfig.copy(tem.commonCheckConfig); + this->checkFunction.copy(tem.checkFunction); + this->baseFunction.copy(tem.baseFunction); + } + void print(std::string str) + { + printf("%s=============AnalysisyConfigST==============\n", str.c_str()); + checkFunction.print("checkFunction"); + baseFunction.print("baseFunction"); + printf("%s============AnalysisyConfigST===============\n", str.c_str()); + } +}; +// 金佰利 图片亮度值 参数 后来添加的 +struct ImgBrightnessROIConfig +{ + bool bcheck; + cv::Rect imageBrightnessROI; // 图像亮度检测区域 + int minthreshold; // 最小灰度阈值 + int maxthreshold; // 最大灰度阈值 + int alarmSheet; // 检测张数 + ImgBrightnessROIConfig() + { + bcheck = false; + imageBrightnessROI = cv::Rect(0, 0, 0, 0); + minthreshold = 0; + maxthreshold = 0; + alarmSheet = 0; + } + void copy(ImgBrightnessROIConfig tem) + { + this->bcheck = tem.bcheck; + this->imageBrightnessROI = tem.imageBrightnessROI; + this->maxthreshold = tem.maxthreshold; + this->minthreshold = tem.minthreshold; + this->alarmSheet = tem.alarmSheet; + } +}; + +// 预处理图片参数信息 +struct PreDealImgConfig +{ + // 图片预处理: + // 1:cut到指定大小 + // 2、bresize = true, 缩放到模型输入图片尺寸大小 + // 3、bInAI_ImgFflip 输入模型的图片是否要 水平翻转 + // 4、bOutAI_ImgFflip 模型输出的图片是否要 水平翻转 + cv::Rect cutRoi; // 图片裁剪区域信息 + bool bresize; // 是否要resize 到模型输入图尺寸大小 + bool bInAI_ImgFflip; // 模型输入的图片是否翻转 + bool bOutAI_ImgFflip; // 模型输出的图片是否翻转 + PreDealImgConfig() + { + cutRoi.x = 0; + cutRoi.y = 0; + cutRoi.width = 0; + cutRoi.height = 0; + bInAI_ImgFflip = false; + bOutAI_ImgFflip = false; + bresize = false; + } + void copy(PreDealImgConfig tem) + { + this->cutRoi.x = tem.cutRoi.x; + this->cutRoi.y = tem.cutRoi.y; + this->cutRoi.width = tem.cutRoi.width; + this->cutRoi.height = tem.cutRoi.height; + this->bInAI_ImgFflip = tem.bInAI_ImgFflip; + this->bOutAI_ImgFflip = tem.bOutAI_ImgFflip; + this->bresize = tem.bresize; + } +}; + +// 检测基本参数,包括基本信息,和深度学习模型路径参数 +struct CheckConfigST +{ + ImageInfo Srcimg_in; + ImageInfo resultimg_out; + PreDealImgConfig preDealImgConfig; + ModelConfigST modelConfig; // 深度模型参数 + CAM_CONFIGINFO_ camConfig; + CheckConfigST() + { + } + void copy(CheckConfigST tem) + { + this->preDealImgConfig.copy(tem.preDealImgConfig); + this->modelConfig.copy(tem.modelConfig); + this->Srcimg_in.copy(tem.Srcimg_in); + this->resultimg_out.copy(tem.resultimg_out); + this->camConfig.copy(tem.camConfig); + } +}; +struct BLobResult +{ + int nresult; // 最后的结果 + cv::Rect roi; // 位置 + int AI_qx_type; // 缺陷类型, + int area; // Blob- 面积 + int energy; // Blob-能量 + float JudgArea; // Blob- 调整后的面积 平方毫米 + float len; // Blob- 长度 + int maxValue; // Blob- 最大亮度 + float grayDis; // Blob- 灰阶 + float density; // Blob- 密度 + BLobResult() + { + Init(); + } + void Init() + { + nresult = 0; // 最后的结果 + roi = {0, 0, 0, 0}; // 位置 + AI_qx_type = 0; // 缺陷类型, + area = 0; // Blob- 面积 + energy = 0; // Blob-能量 + JudgArea = 0; // Blob- 调整后的面积 平方毫米 + len = 0; // Blob- 长度 + maxValue = 0; // Blob- 最大亮度 + grayDis = 0; // Blob- 灰阶 + density = 0; // Blob- 密度 + } +}; +// 检测结果 +struct DetResultST +{ + std::vector BLobResultList; + DetResultST() + { + Init(); + } + void Init() + { + BLobResultList.erase(BLobResultList.begin(), BLobResultList.end()); + BLobResultList.clear(); + } + void copy(DetResultST tem) + { + this->BLobResultList.assign(tem.BLobResultList.begin(), tem.BLobResultList.end()); + } +}; +#endif //_CORELOGICFACTORY_HPP_ \ No newline at end of file diff --git a/ConfigModule/include/ConfigBase.h b/ConfigModule/include/ConfigBase.h new file mode 100644 index 0000000..d24e498 --- /dev/null +++ b/ConfigModule/include/ConfigBase.h @@ -0,0 +1,92 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-09-11 15:32:54 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-13 18:49:40 + * @FilePath: /BOE_CELL_AOI_Detect/ConfigModule/include/ConfigBase.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#ifndef ConfigBase_H_ +#define ConfigBase_H_ +#include +#include +#include + +#define CONFIGBASE_VERSION 4 +#define EMPTY_CONFIG_NAME "ALL" +enum CONFIG_TYPE_ +{ + ConfigType_Analysisy_Common_XL, + ConfigType_Check_XL, + ConfigType_Image_In, + ConfigType_Image_out, + ConfigType_BloB, + ConfigType_Count, +}; +struct ImageInfo +{ + int width; + int height; + int channels; + ImageInfo() + { + width = 0; + height = 0; + channels = 0; + } + void copy(ImageInfo tem) + { + + this->width = tem.width; + this->height = tem.height; + this->channels = tem.channels; + } + void print(std::string str) + { + printf("%s width=%d height=%d channels=%d\n", str.c_str(), width, height, channels); + } +}; +class ConfigBase +{ +protected: + ConfigBase() {} + +public: + // delete camera interface + ~ConfigBase() {} + static std::shared_ptr GetInstance(); + virtual int GetConfigIdx() = 0; + // 获取参数更新状态 true 有更新 + virtual bool GetConfigUpdataStatus(int nConfigType, int nidx) = 0; + // 复制想使用的参数 + virtual int GetConfig(int nConfigType, void *pconfig) = 0; + + // 更新参数 pconfig 参数指针,nConfigType 需要更新的参数类型 返回:0 成功 其他异常 + virtual int UpdateConfig(void *pconfig, int nConfigType) = 0; + virtual int UpdateJSONConfig(void *pconfig, int nConfigType) = 0; + + // 返回检测版本信息 + virtual std::string GetVersion() = 0; + // 返回错误信息 + virtual std::string GetErrorInfo() = 0; +}; +class ConfigManagerBase +{ +protected: + ConfigManagerBase() {} + +public: + // delete camera interface + ~ConfigManagerBase() {} + static ConfigManagerBase *GetInstance(); + virtual int LoadAnalysisConfig(std::string strConfigPath) = 0; + virtual int UpdateConfig() = 0; + virtual int GetConfig(int nConfigType, void *pconfig) = 0; + virtual std::string GetJsonPath() = 0; + static ConfigManagerBase *m_pInstance; + +public: + std::unordered_map> Config_instances_; +}; + +#endif \ No newline at end of file diff --git a/ConfigModule/include/ConfigInstance.h b/ConfigModule/include/ConfigInstance.h new file mode 100644 index 0000000..da5281c --- /dev/null +++ b/ConfigModule/include/ConfigInstance.h @@ -0,0 +1,49 @@ +#ifndef ConfigInstance_H_ +#define ConfigInstance_H_ +#include "JsonCoversion.h" +#include +#include +#include +#include +#include "ConfigBase.h" +#include "Define.h" +#include "JsonConfig.h" +#include "CheckConfigDefine.h" +class ConfigInstance : public ConfigBase +{ + +public: + ConfigInstance(); + ~ConfigInstance(); + int GetConfigIdx(); + bool GetConfigUpdataStatus(int nConfigType, int nidx); + // 获取想使用的参数 + int GetConfig(int nConfigType, void *pconfig); + // 更新参数 pconfig 参数指针,nConfigType 需要更新的参数类型 返回:0 成功 其他异常 + int UpdateConfig(void *pconfig, int nConfigType); + int UpdateJSONConfig(void *pconfig, int nConfigType); + // 返回检测版本信息 + std::string GetVersion(); + // 返回错误信息 + std::string GetErrorInfo(); + +private: + // updata analysis cofnig + int Updata_analysis(Json::Value json_value); + int Updata_Check(Json::Value json_value); + // 设置 参数更新状态 + int SetStatus(int nConfigType); + // 成员变量 +private: + int m_ErrorValue; // 错误代码 + std::mutex mutex_status; + + bool m_USER_ConfigUpdataStatusList[ConfigType_Count][MAX_USER_COUNT]; + + AnalysisyConfigST m_AnalysisyConfig; + CheckConfigST m_CheckConfig; + std::mutex mtx_GetIdx; // + int m_nCurIdx; +}; + +#endif \ No newline at end of file diff --git a/ConfigModule/include/ConfigManager.h b/ConfigModule/include/ConfigManager.h new file mode 100644 index 0000000..de71004 --- /dev/null +++ b/ConfigModule/include/ConfigManager.h @@ -0,0 +1,44 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-07-09 13:57:25 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-11 21:57:35 + * @FilePath: /BOE_Bounding/ConfigModule/include/ConfigBase.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#ifndef ConfigManager_H_ +#define ConfigManager_H_ +#include "JsonCoversion.h" +#include +#include +#include +#include +#include +#include "ConfigBase.h" +#include "Define.h" +#include "JsonConfig.h" +#include "CheckConfigDefine.h" +#include + +using namespace std; +namespace fs = std::filesystem; + +class ConfigManager : public ConfigManagerBase +{ +public: + ConfigManager(); + ~ConfigManager(); + + int LoadAnalysisConfig(std::string strConfigPath); + int UpdateConfig(); + int GetConfig(int nConfigType, void *pconfig); + std::string GetJsonPath(); + +private: + int LoadParamConfig(std::shared_ptr &Config, std::string strConfigPath); + +private: + std::string m_strConfigRootPath; +}; + +#endif \ No newline at end of file diff --git a/ConfigModule/include/Define.h b/ConfigModule/include/Define.h new file mode 100644 index 0000000..9b511db --- /dev/null +++ b/ConfigModule/include/Define.h @@ -0,0 +1,46 @@ +#ifndef Define_H_ +#define Define_H_ +#include + +// 参数使用最大的用户数 用以更新 参数使用 +#define MAX_USER_COUNT 10 + +enum ERROR_TYPE_Config_ +{ + ERROR_Type_Ok, + ERROR_Type_JsonNull, + ERROR_Type_ConfigType, + ERROR_Type_Count, +}; +static const std::string ERROR_TYPE_Names[] = + { + "OK", + "Json Is Null", + "Config Type Error"}; + +struct CommonParamST +{ + std::string image; + std::string skuName; + std::string value; + CommonParamST() + { + image = ""; + value = ""; + skuName = ""; + } + void copy(CommonParamST tem) + { + this->image = tem.image; + this->value = tem.value; + this->skuName = tem.skuName; + } +}; +enum CHECK_INSTUCT_ +{ + CHECK_INSTUCT_NULL = 1, // 空 + CHECK_INSTUCT_WhiteAndBlack = CHECK_INSTUCT_NULL * 2, // WTB,BTW,HB3,HB4 使用单独检查方法 + +}; + +#endif \ No newline at end of file diff --git a/ConfigModule/include/JsonConfig.h b/ConfigModule/include/JsonConfig.h new file mode 100644 index 0000000..b5d7736 --- /dev/null +++ b/ConfigModule/include/JsonConfig.h @@ -0,0 +1,86 @@ +#ifndef CamConfig_H +#define CamConfig_H + +#include "JsonCoversion.h" +#include +#include +#include "CheckConfigDefine.h" +#include "Define.h" + +class CommonParamJson : public JsonCoversion +{ +public: + CommonParamJson() {} + virtual ~CommonParamJson() {} + +public: + virtual Json::Value toJsonValue(); + virtual void toObjectFromValue(Json::Value root); + int GetConfig(CommonParamST &config); + +private: + CommonParamST _config; +}; + +class CommonParamToCheckConfigJson : public JsonCoversion +{ +public: + CommonParamToCheckConfigJson() {} + virtual ~CommonParamToCheckConfigJson() {} + +public: + virtual Json::Value toJsonValue(); + virtual void toObjectFromValue(Json::Value root); + int GetConfig(CommonCheckConfigST &config); + +private: + CommonCheckConfigST _config; +}; + +class CheckConfigJson : public JsonCoversion +{ +public: + CheckConfigJson() {} + virtual ~CheckConfigJson() {} + +public: + virtual Json::Value toJsonValue(); + virtual void toObjectFromValue(Json::Value root); + int GetConfig(CheckConfigST &config); + +private: + CheckConfigST _config; +}; + +class ChannelFuntonConfigJson : public JsonCoversion +{ +public: + ChannelFuntonConfigJson() {} + virtual ~ChannelFuntonConfigJson() {} + +public: + virtual Json::Value toJsonValue(); + virtual void toObjectFromValue(Json::Value root); + int GetConfig(ALLChannelCheckFunction &config); + int GetFunction(Json::Value value, CheckFunction &function); + +private: + ALLChannelCheckFunction _config; +}; + +class BaseFuntonConfigJson : public JsonCoversion +{ +public: + BaseFuntonConfigJson() {} + virtual ~BaseFuntonConfigJson() {} + +public: + virtual Json::Value toJsonValue(); + virtual void toObjectFromValue(Json::Value root); + int GetConfig(BaseCheckFunction &config); + int GetFunction(Json::Value value); + +private: + BaseCheckFunction _config; +}; +#endif // diff --git a/ConfigModule/include/JsonCoversion.h b/ConfigModule/include/JsonCoversion.h new file mode 100644 index 0000000..5419e33 --- /dev/null +++ b/ConfigModule/include/JsonCoversion.h @@ -0,0 +1,31 @@ +#ifndef JsonCoversion_H +#define JsonCoversion_H +#include +#include +#include +#include "json/json.h" +using namespace std; + +class JsonCoversion +{ + protected: + Json::Value root; + + // Json::FastWriter writer; //弃用 改用StreamWriterBuilder + Json::StreamWriterBuilder writerBuilder; + + // Json::Reader reader; //弃用 改用CharReaderBuilder + Json::CharReaderBuilder readerBuilder; + public: + JsonCoversion(); + virtual ~JsonCoversion(); + protected: + public: + string toJson(); + void toObject(string & strBuf); + protected: + virtual Json::Value toJsonValue() = 0; + virtual void toObjectFromValue(Json::Value root) = 0; +}; + +#endif // JsonCoversion_H diff --git a/ConfigModule/include/json/json-forwards.h b/ConfigModule/include/json/json-forwards.h new file mode 100644 index 0000000..45d2e46 --- /dev/null +++ b/ConfigModule/include/json/json-forwards.h @@ -0,0 +1,346 @@ +/// Json-cpp amalgamated forward header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json-forwards.h" +/// This header provides forward declaration for all JsonCpp types. + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED +# define JSON_FORWARD_AMALGAMATED_H_INCLUDED +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +#define JSON_IS_AMALGAMATION + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED +#include +#include //typedef int64_t, uint64_t +#include //typedef String + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of +/// std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgamated header. +// #define JSON_IS_AMALGAMATION + +#ifdef JSON_IN_CPPTL +#include +#ifndef JSON_USE_CPPTL +#define JSON_USE_CPPTL 1 +#endif +#endif + +#ifdef JSON_IN_CPPTL +#define JSON_API CPPTL_API +#elif defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#define JSON_API +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +#if defined(_MSC_VER) // MSVC +#if _MSC_VER <= 1200 // MSVC 6 +// Microsoft Visual Studio 6 only support conversion from __int64 to double +// (no conversion from unsigned __int64). +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' +// characters in the debug information) +// All projects I've ever seen with VS6 were using this globally (not bothering +// with pragma push/pop). +#pragma warning(disable : 4786) +#endif // MSVC 6 + +#if _MSC_VER >= 1500 // MSVC 2008 + /// Indicates that the following function is deprecated. +#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#endif + +#endif // defined(_MSC_VER) + +// In c++11 the override keyword allows you to explicitly define that a function +// is intended to override the base-class version. This makes the code more +// manageable and fixes a set of common hard-to-find bugs. +#if __cplusplus >= 201103L +#define JSONCPP_OVERRIDE override +#define JSONCPP_NOEXCEPT noexcept +#define JSONCPP_OP_EXPLICIT explicit +#elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900 +#define JSONCPP_OVERRIDE override +#define JSONCPP_NOEXCEPT throw() +#if _MSC_VER >= 1800 // MSVC 2013 +#define JSONCPP_OP_EXPLICIT explicit +#else +#define JSONCPP_OP_EXPLICIT +#endif +#elif defined(_MSC_VER) && _MSC_VER >= 1900 +#define JSONCPP_OVERRIDE override +#define JSONCPP_NOEXCEPT noexcept +#define JSONCPP_OP_EXPLICIT explicit +#else +#define JSONCPP_OVERRIDE +#define JSONCPP_NOEXCEPT throw() +#define JSONCPP_OP_EXPLICIT +#endif + +#ifndef JSON_HAS_RVALUE_REFERENCES + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // MSVC >= 2010 + +#ifdef __clang__ +#if __has_feature(cxx_rvalue_references) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // has_feature + +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // GXX_EXPERIMENTAL + +#endif // __clang__ || __GNUC__ + +#endif // not defined JSON_HAS_RVALUE_REFERENCES + +#ifndef JSON_HAS_RVALUE_REFERENCES +#define JSON_HAS_RVALUE_REFERENCES 0 +#endif + +#ifdef __clang__ +#if __has_extension(attribute_deprecated_with_message) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#endif +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +#endif // GNUC version +#endif // __clang__ || __GNUC__ + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if __GNUC__ >= 6 +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +#include "version.h" + +#if JSONCPP_USING_SECURE_MEMORY +#include "allocator.h" //typedef Allocator +#endif + +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { +typedef int Int; +typedef unsigned int UInt; +#if defined(JSON_NO_INT64) +typedef int LargestInt; +typedef unsigned int LargestUInt; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else // if defined(_MSC_VER) // Other platforms, use long long +typedef int64_t Int64; +typedef uint64_t UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) +#if JSONCPP_USING_SECURE_MEMORY +#define JSONCPP_STRING \ + std::basic_string, Json::SecureAllocator > +#define JSONCPP_OSTRINGSTREAM \ + std::basic_ostringstream, \ + Json::SecureAllocator > +#define JSONCPP_OSTREAM std::basic_ostream > +#define JSONCPP_ISTRINGSTREAM \ + std::basic_istringstream, \ + Json::SecureAllocator > +#define JSONCPP_ISTREAM std::istream +#else +#define JSONCPP_STRING std::string +#define JSONCPP_OSTRINGSTREAM std::ostringstream +#define JSONCPP_OSTREAM std::ostream +#define JSONCPP_ISTRINGSTREAM std::istringstream +#define JSONCPP_ISTREAM std::istream +#endif // if JSONCPP_USING_SECURE_MEMORY +} // end namespace Json + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class FastWriter; +class StyledWriter; + +// reader.h +class Reader; + +// features.h +class Features; + +// value.h +typedef unsigned int ArrayIndex; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED diff --git a/ConfigModule/include/json/json.h b/ConfigModule/include/json/json.h new file mode 100644 index 0000000..6d9a0bc --- /dev/null +++ b/ConfigModule/include/json/json.h @@ -0,0 +1,2268 @@ +/// Json-cpp amalgamated header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_AMALGAMATED_H_INCLUDED +# define JSON_AMALGAMATED_H_INCLUDED +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +#define JSON_IS_AMALGAMATION + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + +// DO NOT EDIT. This file (and "version") is generated by CMake. +// Run CMake configure step to update it. +#ifndef JSON_VERSION_H_INCLUDED +#define JSON_VERSION_H_INCLUDED + +#define JSONCPP_VERSION_STRING "1.8.4" +#define JSONCPP_VERSION_MAJOR 1 +#define JSONCPP_VERSION_MINOR 8 +#define JSONCPP_VERSION_PATCH 4 +#define JSONCPP_VERSION_QUALIFIER +#define JSONCPP_VERSION_HEXA \ + ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ + (JSONCPP_VERSION_PATCH << 8)) + +#ifdef JSONCPP_USING_SECURE_MEMORY +#undef JSONCPP_USING_SECURE_MEMORY +#endif +#define JSONCPP_USING_SECURE_MEMORY 0 +// If non-zero, the library zeroes any memory that it has allocated before +// it frees its memory. + +#endif // JSON_VERSION_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED +#include +#include //typedef int64_t, uint64_t +#include //typedef String + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of +/// std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgamated header. +// #define JSON_IS_AMALGAMATION + +#ifdef JSON_IN_CPPTL +#include +#ifndef JSON_USE_CPPTL +#define JSON_USE_CPPTL 1 +#endif +#endif + +#ifdef JSON_IN_CPPTL +#define JSON_API CPPTL_API +#elif defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#define JSON_API +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +#if defined(_MSC_VER) // MSVC +#if _MSC_VER <= 1200 // MSVC 6 +// Microsoft Visual Studio 6 only support conversion from __int64 to double +// (no conversion from unsigned __int64). +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' +// characters in the debug information) +// All projects I've ever seen with VS6 were using this globally (not bothering +// with pragma push/pop). +#pragma warning(disable : 4786) +#endif // MSVC 6 + +#if _MSC_VER >= 1500 // MSVC 2008 + /// Indicates that the following function is deprecated. +#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#endif + +#endif // defined(_MSC_VER) + +// In c++11 the override keyword allows you to explicitly define that a function +// is intended to override the base-class version. This makes the code more +// manageable and fixes a set of common hard-to-find bugs. +#if __cplusplus >= 201103L +#define JSONCPP_OVERRIDE override +#define JSONCPP_NOEXCEPT noexcept +#define JSONCPP_OP_EXPLICIT explicit +#elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900 +#define JSONCPP_OVERRIDE override +#define JSONCPP_NOEXCEPT throw() +#if _MSC_VER >= 1800 // MSVC 2013 +#define JSONCPP_OP_EXPLICIT explicit +#else +#define JSONCPP_OP_EXPLICIT +#endif +#elif defined(_MSC_VER) && _MSC_VER >= 1900 +#define JSONCPP_OVERRIDE override +#define JSONCPP_NOEXCEPT noexcept +#define JSONCPP_OP_EXPLICIT explicit +#else +#define JSONCPP_OVERRIDE +#define JSONCPP_NOEXCEPT throw() +#define JSONCPP_OP_EXPLICIT +#endif + +#ifndef JSON_HAS_RVALUE_REFERENCES + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // MSVC >= 2010 + +#ifdef __clang__ +#if __has_feature(cxx_rvalue_references) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // has_feature + +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // GXX_EXPERIMENTAL + +#endif // __clang__ || __GNUC__ + +#endif // not defined JSON_HAS_RVALUE_REFERENCES + +#ifndef JSON_HAS_RVALUE_REFERENCES +#define JSON_HAS_RVALUE_REFERENCES 0 +#endif + +#ifdef __clang__ +#if __has_extension(attribute_deprecated_with_message) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#endif +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +#endif // GNUC version +#endif // __clang__ || __GNUC__ + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if __GNUC__ >= 6 +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +#include "version.h" + +#if JSONCPP_USING_SECURE_MEMORY +#include "allocator.h" //typedef Allocator +#endif + +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { +typedef int Int; +typedef unsigned int UInt; +#if defined(JSON_NO_INT64) +typedef int LargestInt; +typedef unsigned int LargestUInt; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else // if defined(_MSC_VER) // Other platforms, use long long +typedef int64_t Int64; +typedef uint64_t UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) +#if JSONCPP_USING_SECURE_MEMORY +#define JSONCPP_STRING \ + std::basic_string, Json::SecureAllocator > +#define JSONCPP_OSTRINGSTREAM \ + std::basic_ostringstream, \ + Json::SecureAllocator > +#define JSONCPP_OSTREAM std::basic_ostream > +#define JSONCPP_ISTRINGSTREAM \ + std::basic_istringstream, \ + Json::SecureAllocator > +#define JSONCPP_ISTREAM std::istream +#else +#define JSONCPP_STRING std::string +#define JSONCPP_OSTRINGSTREAM std::ostringstream +#define JSONCPP_OSTREAM std::ostream +#define JSONCPP_ISTRINGSTREAM std::istringstream +#define JSONCPP_ISTREAM std::istream +#endif // if JSONCPP_USING_SECURE_MEMORY +} // end namespace Json + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class FastWriter; +class StyledWriter; + +// reader.h +class Reader; + +// features.h +class Features; + +// value.h +typedef unsigned int ArrayIndex; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/features.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_FEATURES_H_INCLUDED +#define CPPTL_JSON_FEATURES_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +#pragma pack(push, 8) + +namespace Json { + +/** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ +class JSON_API Features { +public: + /** \brief A configuration that allows all features and assumes all strings + * are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON + * specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_; + + /// \c true if root must be either an array or an object value. Default: \c + /// false. + bool strictRoot_; + + /// \c true if dropped null placeholders are allowed. Default: \c false. + bool allowDroppedNullPlaceholders_; + + /// \c true if numeric object key are allowed. Default: \c false. + bool allowNumericKeys_; +}; + +} // namespace Json + +#pragma pack(pop) + +#endif // CPPTL_JSON_FEATURES_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/features.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_H_INCLUDED +#define CPPTL_JSON_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include + +#ifndef JSON_USE_CPPTL_SMALLMAP +#include +#else +#include +#endif +#ifdef JSON_USE_CPPTL +#include +#endif + +// Conditional NORETURN attribute on the throw functions would: +// a) suppress false positives from static code analysis +// b) possibly improve optimization opportunities. +#if !defined(JSONCPP_NORETURN) +#if defined(_MSC_VER) +#define JSONCPP_NORETURN __declspec(noreturn) +#elif defined(__GNUC__) +#define JSONCPP_NORETURN __attribute__((__noreturn__)) +#else +#define JSONCPP_NORETURN +#endif +#endif + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + +/** Base class for all exceptions we throw. + * + * We use nothing but these internally. Of course, STL can throw others. + */ +class JSON_API Exception : public std::exception { +public: + Exception(JSONCPP_STRING const& msg); + ~Exception() JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; + char const* what() const JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; + +protected: + JSONCPP_STRING msg_; +}; + +/** Exceptions which the user cannot easily avoid. + * + * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input + * + * \remark derived from Json::Exception + */ +class JSON_API RuntimeError : public Exception { +public: + RuntimeError(JSONCPP_STRING const& msg); +}; + +/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. + * + * These are precondition-violations (user bugs) and internal errors (our bugs). + * + * \remark derived from Json::Exception + */ +class JSON_API LogicError : public Exception { +public: + LogicError(JSONCPP_STRING const& msg); +}; + +/// used internally +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg); +/// used internally +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg); + +/** \brief Type of the value held by a Value object. + */ +enum ValueType { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). +}; + +enum CommentPlacement { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for + /// root value) + numberOfCommentPlacement +}; + +/** \brief Type of precision for formatting of real values. + */ +enum PrecisionType { + significantDigits = 0, ///< we set max number of significant digits in string + decimalPlaces ///< we set max number of digits after "." in string +}; + +//# ifdef JSON_USE_CPPTL +// typedef CppTL::AnyEnumerator EnumMemberNames; +// typedef CppTL::AnyEnumerator EnumValues; +//# endif + +/** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignment takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ +class JSON_API StaticString { +public: + explicit StaticString(const char* czstring) : c_str_(czstring) {} + + operator const char*() const { return c_str_; } + + const char* c_str() const { return c_str_; } + +private: + const char* c_str_; +}; + +/** \brief Represents a JSON value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * Values of an #objectValue or #arrayValue can be accessed using operator[]() + * methods. + * Non-const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resized and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtain default value in the case the + * required element does not exist. + * + * It is possible to iterate over the list of a #objectValue values using + * the getMemberNames() method. + * + * \note #Value string-length fit in size_t, but keys must be < 2^30. + * (The reason is an implementation detail.) A #CharReader will raise an + * exception if a bound is exceeded to avoid security holes in your app, + * but the Value API does *not* check bounds. That is the responsibility + * of the caller. + */ +class JSON_API Value { + friend class ValueIteratorBase; + +public: + typedef std::vector Members; + typedef ValueIterator iterator; + typedef ValueConstIterator const_iterator; + typedef Json::UInt UInt; + typedef Json::Int Int; +#if defined(JSON_HAS_INT64) + typedef Json::UInt64 UInt64; + typedef Json::Int64 Int64; +#endif // defined(JSON_HAS_INT64) + typedef Json::LargestInt LargestInt; + typedef Json::LargestUInt LargestUInt; + typedef Json::ArrayIndex ArrayIndex; + + // Required for boost integration, e. g. BOOST_TEST + typedef std::string value_type; + + static const Value& null; ///< We regret this reference to a global instance; + ///< prefer the simpler Value(). + static const Value& nullRef; ///< just a kludge for binary-compatibility; same + ///< as null + static Value const& nullSingleton(); ///< Prefer this to null or nullRef. + + /// Minimum signed integer value that can be stored in a Json::Value. + static const LargestInt minLargestInt; + /// Maximum signed integer value that can be stored in a Json::Value. + static const LargestInt maxLargestInt; + /// Maximum unsigned integer value that can be stored in a Json::Value. + static const LargestUInt maxLargestUInt; + + /// Minimum signed int value that can be stored in a Json::Value. + static const Int minInt; + /// Maximum signed int value that can be stored in a Json::Value. + static const Int maxInt; + /// Maximum unsigned int value that can be stored in a Json::Value. + static const UInt maxUInt; + +#if defined(JSON_HAS_INT64) + /// Minimum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 minInt64; + /// Maximum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 maxInt64; + /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. + static const UInt64 maxUInt64; +#endif // defined(JSON_HAS_INT64) + + /// Default precision for real value for string representation. + static const UInt defaultRealPrecision; + +// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler +// when using gcc and clang backend compilers. CZString +// cannot be defined as private. See issue #486 +#ifdef __NVCC__ +public: +#else +private: +#endif +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + class CZString { + public: + enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy }; + CZString(ArrayIndex index); + CZString(char const* str, unsigned length, DuplicationPolicy allocate); + CZString(CZString const& other); +#if JSON_HAS_RVALUE_REFERENCES + CZString(CZString&& other); +#endif + ~CZString(); + CZString& operator=(const CZString& other); + +#if JSON_HAS_RVALUE_REFERENCES + CZString& operator=(CZString&& other); +#endif + + bool operator<(CZString const& other) const; + bool operator==(CZString const& other) const; + ArrayIndex index() const; + // const char* c_str() const; ///< \deprecated + char const* data() const; + unsigned length() const; + bool isStaticString() const; + + private: + void swap(CZString& other); + + struct StringStorage { + unsigned policy_ : 2; + unsigned length_ : 30; // 1GB max + }; + + char const* cstr_; // actually, a prefixed string, unless policy is noDup + union { + ArrayIndex index_; + StringStorage storage_; + }; + }; + +public: +#ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map ObjectValues; +#else + typedef CppTL::SmallMap ObjectValues; +#endif // ifndef JSON_USE_CPPTL_SMALLMAP +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + +public: + /** \brief Create a default Value of the given type. + + This is a very useful constructor. + To create an empty array, pass arrayValue. + To create an empty object, pass objectValue. + Another Value can then be set to this one by assignment. +This is useful since clear() and resize() will not alter types. + + Examples: +\code +Json::Value null_value; // null +Json::Value arr_value(Json::arrayValue); // [] +Json::Value obj_value(Json::objectValue); // {} +\endcode + */ + Value(ValueType type = nullValue); + Value(Int value); + Value(UInt value); +#if defined(JSON_HAS_INT64) + Value(Int64 value); + Value(UInt64 value); +#endif // if defined(JSON_HAS_INT64) + Value(double value); + Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) + Value(const char* begin, const char* end); ///< Copy all, incl zeroes. + /** \brief Constructs a value from a static string. + + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to this + * constructor. + * \note This works only for null-terminated strings. (We cannot change the + * size of this class, so we have nowhere to store the length, + * which might be computed later for various operations.) + * + * Example of usage: + * \code + * static StaticString foo("some text"); + * Json::Value aValue(foo); + * \endcode + */ + Value(const StaticString& value); + Value(const JSONCPP_STRING& value); ///< Copy data() til size(). Embedded + ///< zeroes too. +#ifdef JSON_USE_CPPTL + Value(const CppTL::ConstString& value); +#endif + Value(bool value); + /// Deep copy. + Value(const Value& other); +#if JSON_HAS_RVALUE_REFERENCES + /// Move constructor + Value(Value&& other); +#endif + ~Value(); + + /// Deep copy, then swap(other). + /// \note Over-write existing comments. To preserve comments, use + /// #swapPayload(). + Value& operator=(Value other); + + /// Swap everything. + void swap(Value& other); + /// Swap values but leave comments and source offsets in place. + void swapPayload(Value& other); + + /// copy everything. + void copy(const Value& other); + /// copy values but leave comments and source offsets in place. + void copyPayload(const Value& other); + + ValueType type() const; + + /// Compare payload only, not comments etc. + bool operator<(const Value& other) const; + bool operator<=(const Value& other) const; + bool operator>=(const Value& other) const; + bool operator>(const Value& other) const; + bool operator==(const Value& other) const; + bool operator!=(const Value& other) const; + int compare(const Value& other) const; + + const char* asCString() const; ///< Embedded zeroes could cause you trouble! +#if JSONCPP_USING_SECURE_MEMORY + unsigned getCStringLength() const; // Allows you to understand the length of + // the CString +#endif + JSONCPP_STRING asString() const; ///< Embedded zeroes are possible. + /** Get raw char* of string-value. + * \return false if !string. (Seg-fault if str or end are NULL.) + */ + bool getString(char const** begin, char const** end) const; +#ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +#endif + Int asInt() const; + UInt asUInt() const; +#if defined(JSON_HAS_INT64) + Int64 asInt64() const; + UInt64 asUInt64() const; +#endif // if defined(JSON_HAS_INT64) + LargestInt asLargestInt() const; + LargestUInt asLargestUInt() const; + float asFloat() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isInt64() const; + bool isUInt() const; + bool isUInt64() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + bool isConvertibleTo(ValueType other) const; + + /// Number of values in array or object + ArrayIndex size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return !isNull() + JSONCPP_OP_EXPLICIT operator bool() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to newSize elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize(ArrayIndex newSize); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are + /// inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](ArrayIndex index); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are + /// inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](int index); + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](ArrayIndex index) const; + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](int index) const; + + /// If the array contains at least index+1 elements, returns the element + /// value, + /// otherwise returns defaultValue. + Value get(ArrayIndex index, const Value& defaultValue) const; + /// Return true if index < size(). + bool isValidIndex(ArrayIndex index) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value& append(const Value& value); + +#if JSON_HAS_RVALUE_REFERENCES + Value& append(Value&& value); +#endif + + /// Access an object value by name, create a null member if it does not exist. + /// \note Because of our implementation, keys are limited to 2^30 -1 chars. + /// Exceeding that will cause an exception. + Value& operator[](const char* key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const char* key) const; + /// Access an object value by name, create a null member if it does not exist. + /// \param key may contain embedded nulls. + Value& operator[](const JSONCPP_STRING& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + /// \param key may contain embedded nulls. + const Value& operator[](const JSONCPP_STRING& key) const; + /** \brief Access an object value by name, create a null member if it does not + exist. + + * If the object has no entry for that name, then the member name used to + store + * the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value& operator[](const StaticString& key); +#ifdef JSON_USE_CPPTL + /// Access an object value by name, create a null member if it does not exist. + Value& operator[](const CppTL::ConstString& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const CppTL::ConstString& key) const; +#endif + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const char* key, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \note key may contain embedded nulls. + Value + get(const char* begin, const char* end, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \param key may contain embedded nulls. + Value get(const JSONCPP_STRING& key, const Value& defaultValue) const; +#ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const CppTL::ConstString& key, const Value& defaultValue) const; +#endif + /// Most general and efficient version of isMember()const, get()const, + /// and operator[]const + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + Value const* find(char const* begin, char const* end) const; + /// Most general and efficient version of object-mutators. + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. + Value const* demand(char const* begin, char const* end); + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \return the removed Value, or null. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + /// \deprecated + void removeMember(const char* key); + /// Same as removeMember(const char*) + /// \param key may contain embedded nulls. + /// \deprecated + void removeMember(const JSONCPP_STRING& key); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); + /** \brief Remove the named map member. + + Update 'removed' iff removed. + \param key may contain embedded nulls. + \return true iff removed (no exceptions) + */ + bool removeMember(JSONCPP_STRING const& key, Value* removed); + /// Same as removeMember(JSONCPP_STRING const& key, Value* removed) + bool removeMember(const char* begin, const char* end, Value* removed); + /** \brief Remove the indexed array element. + + O(n) expensive operations. + Update 'removed' iff removed. + \return true if removed (no exceptions) + */ + bool removeIndex(ArrayIndex index, Value* removed); + + /// Return true if the object has a member named key. + /// \note 'key' must be null-terminated. + bool isMember(const char* key) const; + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. + bool isMember(const JSONCPP_STRING& key) const; + /// Same as isMember(JSONCPP_STRING const& key)const + bool isMember(const char* begin, const char* end) const; +#ifdef JSON_USE_CPPTL + /// Return true if the object has a member named key. + bool isMember(const CppTL::ConstString& key) const; +#endif + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + + //# ifdef JSON_USE_CPPTL + // EnumMemberNames enumMemberNames() const; + // EnumValues enumValues() const; + //# endif + + /// \deprecated Always pass len. + JSONCPP_DEPRECATED("Use setComment(JSONCPP_STRING const&) instead.") + void setComment(const char* comment, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const char* comment, size_t len, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const JSONCPP_STRING& comment, CommentPlacement placement); + bool hasComment(CommentPlacement placement) const; + /// Include delimiters and embedded newlines. + JSONCPP_STRING getComment(CommentPlacement placement) const; + + JSONCPP_STRING toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + // Accessors for the [start, limit) range of bytes within the JSON text from + // which this value was parsed, if any. + void setOffsetStart(ptrdiff_t start); + void setOffsetLimit(ptrdiff_t limit); + ptrdiff_t getOffsetStart() const; + ptrdiff_t getOffsetLimit() const; + +private: + void initBasic(ValueType type, bool allocated = false); + void dupPayload(const Value& other); + void releasePayload(); + void dupMeta(const Value& other); + + Value& resolveReference(const char* key); + Value& resolveReference(const char* key, const char* end); + + struct CommentInfo { + CommentInfo(); + ~CommentInfo(); + + void setComment(const char* text, size_t len); + + char* comment_; + }; + + // struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder { + LargestInt int_; + LargestUInt uint_; + double real_; + bool bool_; + char* string_; // actually ptr to unsigned, followed by str, unless + // !allocated_ + ObjectValues* map_; + } value_; + ValueType type_ : 8; + unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is + // useless. If not allocated_, string_ must be + // null-terminated. + CommentInfo* comments_; + + // [start, limit) byte offsets in the source JSON text from which this Value + // was extracted. + ptrdiff_t start_; + ptrdiff_t limit_; +}; + +/** \brief Experimental and untested: represents an element of the "path" to + * access a node. + */ +class JSON_API PathArgument { +public: + friend class Path; + + PathArgument(); + PathArgument(ArrayIndex index); + PathArgument(const char* key); + PathArgument(const JSONCPP_STRING& key); + +private: + enum Kind { kindNone = 0, kindIndex, kindKey }; + JSONCPP_STRING key_; + ArrayIndex index_; + Kind kind_; +}; + +/** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provied as parameter + */ +class JSON_API Path { +public: + Path(const JSONCPP_STRING& path, + const PathArgument& a1 = PathArgument(), + const PathArgument& a2 = PathArgument(), + const PathArgument& a3 = PathArgument(), + const PathArgument& a4 = PathArgument(), + const PathArgument& a5 = PathArgument()); + + const Value& resolve(const Value& root) const; + Value resolve(const Value& root, const Value& defaultValue) const; + /// Creates the "path" to access the specified node and returns a reference on + /// the node. + Value& make(Value& root) const; + +private: + typedef std::vector InArgs; + typedef std::vector Args; + + void makePath(const JSONCPP_STRING& path, const InArgs& in); + void addPathInArg(const JSONCPP_STRING& path, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind); + static void invalidPath(const JSONCPP_STRING& path, int location); + + Args args_; +}; + +/** \brief base class for Value iterators. + * + */ +class JSON_API ValueIteratorBase { +public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + bool operator==(const SelfType& other) const { return isEqual(other); } + + bool operator!=(const SelfType& other) const { return !isEqual(other); } + + difference_type operator-(const SelfType& other) const { + return other.computeDistance(*this); + } + + /// Return either the index or the member name of the referenced value as a + /// Value. + Value key() const; + + /// Return the index of the referenced Value, or -1 if it is not an + /// arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value, or "" if it is not an + /// objectValue. + /// \note Avoid `c_str()` on result, as embedded zeroes are possible. + JSONCPP_STRING name() const; + + /// Return the member name of the referenced Value. "" if it is not an + /// objectValue. + /// \deprecated This cannot be used for UTF-8 strings, since there can be + /// embedded nulls. + JSONCPP_DEPRECATED("Use `key = name();` instead.") + char const* memberName() const; + /// Return the member name of the referenced Value, or NULL if it is not an + /// objectValue. + /// \note Better version than memberName(). Allows embedded nulls. + char const* memberName(char const** end) const; + +protected: + Value& deref() const; + + void increment(); + + void decrement(); + + difference_type computeDistance(const SelfType& other) const; + + bool isEqual(const SelfType& other) const; + + void copy(const SelfType& other); + +private: + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; + +public: + // For some reason, BORLAND needs these at the end, rather + // than earlier. No idea why. + ValueIteratorBase(); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); +}; + +/** \brief const iterator for object and array value. + * + */ +class JSON_API ValueConstIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef const Value value_type; + // typedef unsigned int size_t; + // typedef int difference_type; + typedef const Value& reference; + typedef const Value* pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); + ValueConstIterator(ValueIterator const& other); + +private: + /*! \internal Use by Value to create an iterator. + */ + explicit ValueConstIterator(const Value::ObjectValues::iterator& current); + +public: + SelfType& operator=(const ValueIteratorBase& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +/** \brief Iterator for object and array value. + */ +class JSON_API ValueIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef Value value_type; + typedef unsigned int size_t; + typedef int difference_type; + typedef Value& reference; + typedef Value* pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + explicit ValueIterator(const ValueConstIterator& other); + ValueIterator(const ValueIterator& other); + +private: + /*! \internal Use by Value to create an iterator. + */ + explicit ValueIterator(const Value::ObjectValues::iterator& current); + +public: + SelfType& operator=(const SelfType& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +inline void swap(Value& a, Value& b) { a.swap(b); } + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_READER_H_INCLUDED +#define CPPTL_JSON_READER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "features.h" +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +namespace Json { + +/** \brief Unserialize a JSON document into a + *Value. + * + * \deprecated Use CharReader and CharReaderBuilder. + */ +class JSON_API Reader { +public: + typedef char Char; + typedef const Char* Location; + + /** \brief An error tagged with where in the JSON text it was encountered. + * + * The offsets give the [start, limit) range of bytes within the text. Note + * that this is bytes, not codepoints. + * + */ + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; + }; + + /** \brief Constructs a Reader allowing all features + * for parsing. + */ + JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set + * for parsing. + */ + JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") + Reader(const Features& features); + + /** \brief Read a Value from a JSON + * document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them + * back during + * serialization, \c false to discard comments. + * This parameter is ignored if + * Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + bool + parse(const std::string& document, Value& root, bool collectComments = true); + + /** \brief Read a Value from a JSON + document. + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the + document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + document to read. + * Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them + back during + * serialization, \c false to discard comments. + * This parameter is ignored if + Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse(JSONCPP_ISTREAM& is, Value& root, bool collectComments = true); + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * \return Formatted error message with the list of errors with their location + * in + * the parsed document. An empty string is returned if no error + * occurred + * during parsing. + * \deprecated Use getFormattedErrorMessages() instead (typo fix). + */ + JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") + JSONCPP_STRING getFormatedErrorMessages() const; + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * \return Formatted error message with the list of errors with their location + * in + * the parsed document. An empty string is returned if no error + * occurred + * during parsing. + */ + JSONCPP_STRING getFormattedErrorMessages() const; + + /** \brief Returns a vector of structured erros encounted while parsing. + * \return A (possibly empty) vector of StructuredError objects. Currently + * only one error can be returned, but the caller should tolerate + * multiple + * errors. This can occur if the parser recovers from a non-fatal + * parse error and then encounters additional errors. + */ + std::vector getStructuredErrors() const; + + /** \brief Add a semantic error message. + * \param value JSON Value location associated with the error + * \param message The error message. + * \return \c true if the error was successfully added, \c false if the + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const JSONCPP_STRING& message); + + /** \brief Add a semantic error message with extra context. + * \param value JSON Value location associated with the error + * \param message The error message. + * \param extra Additional JSON Value location to contextualize the error + * \return \c true if the error was successfully added, \c false if either + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, + const JSONCPP_STRING& message, + const Value& extra); + + /** \brief Return whether there are any errors. + * \return \c true if there are no errors to report \c false if + * errors have occurred. + */ + bool good() const; + +private: + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + JSONCPP_STRING message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, JSONCPP_STRING& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool + addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + JSONCPP_STRING getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + static bool containsNewLine(Location begin, Location end); + static JSONCPP_STRING normalizeEOL(Location begin, Location end); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + JSONCPP_STRING document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + JSONCPP_STRING commentsBefore_; + Features features_; + bool collectComments_; +}; // Reader + +/** Interface for reading JSON from a char array. + */ +class JSON_API CharReader { +public: + virtual ~CharReader() {} + /** \brief Read a Value from a JSON + document. + * The document must be a UTF-8 encoded string containing the document to + read. + * + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the + document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + document to read. + * Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param errs [out] Formatted error messages (if not NULL) + * a user friendly string that lists errors in the parsed + * document. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + virtual bool parse(char const* beginDoc, + char const* endDoc, + Value* root, + JSONCPP_STRING* errs) = 0; + + class JSON_API Factory { + public: + virtual ~Factory() {} + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual CharReader* newCharReader() const = 0; + }; // Factory +}; // CharReader + +/** \brief Build a CharReader implementation. + +Usage: +\code + using namespace Json; + CharReaderBuilder builder; + builder["collectComments"] = false; + Value value; + JSONCPP_STRING errs; + bool ok = parseFromStream(builder, std::cin, &value, &errs); +\endcode +*/ +class JSON_API CharReaderBuilder : public CharReader::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + These are case-sensitive. + Available settings (case-sensitive): + - `"collectComments": false or true` + - true to collect comment and allow writing them + back during serialization, false to discard comments. + This parameter is ignored if allowComments is false. + - `"allowComments": false or true` + - true if comments are allowed. + - `"strictRoot": false or true` + - true if root must be either an array or an object value + - `"allowDroppedNullPlaceholders": false or true` + - true if dropped null placeholders are allowed. (See + StreamWriterBuilder.) + - `"allowNumericKeys": false or true` + - true if numeric object keys are allowed. + - `"allowSingleQuotes": false or true` + - true if '' are allowed for strings (both keys and values) + - `"stackLimit": integer` + - Exceeding stackLimit (recursive depth of `readValue()`) will + cause an exception. + - This is a security issue (seg-faults caused by deeply nested JSON), + so the default is low. + - `"failIfExtra": false or true` + - If true, `parse()` returns false when extra non-whitespace trails + the JSON value in the input string. + - `"rejectDupKeys": false or true` + - If true, `parse()` returns false when a key is duplicated within an + object. + - `"allowSpecialFloats": false or true` + - If true, special float values (NaNs and infinities) are allowed + and their values are lossfree restorable. + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + CharReaderBuilder(); + ~CharReaderBuilder() JSONCPP_OVERRIDE; + + CharReader* newCharReader() const JSONCPP_OVERRIDE; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + + /** A simple way to update a specific setting. + */ + Value& operator[](JSONCPP_STRING key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults + */ + static void setDefaults(Json::Value* settings); + /** Same as old Features::strictMode(). + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode + */ + static void strictMode(Json::Value* settings); +}; + +/** Consume entire stream and use its begin/end. + * Someday we might have a real StreamReader, but for now this + * is convenient. + */ +bool JSON_API parseFromStream(CharReader::Factory const&, + JSONCPP_ISTREAM&, + Value* root, + std::string* errs); + +/** \brief Read from 'sin' into 'root'. + + Always keep comments from the input JSON. + + This can be used to read a file into a particular sub-object. + For example: + \code + Json::Value root; + cin >> root["dir"]["file"]; + cout << root; + \endcode + Result: + \verbatim + { + "dir": { + "file": { + // The input stream JSON would be nested here. + } + } + } + \endverbatim + \throw std::exception on parse error. + \see Json::operator<<() +*/ +JSON_API JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM&, Value&); + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_READER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_WRITER_H_INCLUDED +#define JSON_WRITER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) && defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +namespace Json { + +class Value; + +/** + +Usage: +\code + using namespace Json; + void writeToStdout(StreamWriter::Factory const& factory, Value const& value) { + std::unique_ptr const writer( + factory.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush + } +\endcode +*/ +class JSON_API StreamWriter { +protected: + JSONCPP_OSTREAM* sout_; // not owned; will not delete +public: + StreamWriter(); + virtual ~StreamWriter(); + /** Write Value into document as configured in sub-class. + Do not take ownership of sout, but maintain a reference during function. + \pre sout != NULL + \return zero on success (For now, we always return zero, so check the + stream instead.) \throw std::exception possibly, depending on configuration + */ + virtual int write(Value const& root, JSONCPP_OSTREAM* sout) = 0; + + /** \brief A simple abstract factory. + */ + class JSON_API Factory { + public: + virtual ~Factory(); + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual StreamWriter* newStreamWriter() const = 0; + }; // Factory +}; // StreamWriter + +/** \brief Write into stringstream, then return string, for convenience. + * A StreamWriter will be created from the factory, used, and then deleted. + */ +JSONCPP_STRING JSON_API writeString(StreamWriter::Factory const& factory, + Value const& root); + +/** \brief Build a StreamWriter implementation. + +Usage: +\code + using namespace Json; + Value value = ...; + StreamWriterBuilder builder; + builder["commentStyle"] = "None"; + builder["indentation"] = " "; // or whatever you like + std::unique_ptr writer( + builder.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush +\endcode +*/ +class JSON_API StreamWriterBuilder : public StreamWriter::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + Available settings (case-sensitive): + - "commentStyle": "None" or "All" + - "indentation": "". + - Setting this to an empty string also omits newline characters. + - "enableYAMLCompatibility": false or true + - slightly change the whitespace around colons + - "dropNullPlaceholders": false or true + - Drop the "null" string from the writer's output for nullValues. + Strictly speaking, this is not valid JSON. But when the output is being + fed to a browser's JavaScript, it makes for smaller output and the + browser can handle the output just fine. + - "useSpecialFloats": false or true + - If true, outputs non-finite floating point values in the following way: + NaN values as "NaN", positive infinity as "Infinity", and negative + infinity as "-Infinity". + - "precision": int + - Number of precision digits for formatting of real values. + - "precisionType": "significant"(default) or "decimal" + - Type of precision for formatting of real values. + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + StreamWriterBuilder(); + ~StreamWriterBuilder() JSONCPP_OVERRIDE; + + /** + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + /** A simple way to update a specific setting. + */ + Value& operator[](JSONCPP_STRING key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults + */ + static void setDefaults(Json::Value* settings); +}; + +/** \brief Abstract class for writers. + * \deprecated Use StreamWriter. (And really, this is an implementation detail.) + */ +class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer { +public: + virtual ~Writer(); + + virtual JSONCPP_STRING write(const Value& root) = 0; +}; + +/** \brief Outputs a Value in JSON format + *without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' + *consumption, + * but may be useful to support feature such as RPC where bandwidth is limited. + * \sa Reader, Value + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter + : public Writer { +public: + FastWriter(); + ~FastWriter() JSONCPP_OVERRIDE {} + + void enableYAMLCompatibility(); + + /** \brief Drop the "null" string from the writer's output for nullValues. + * Strictly speaking, this is not valid JSON. But when the output is being + * fed to a browser's JavaScript, it makes for smaller output and the + * browser can handle the output just fine. + */ + void dropNullPlaceholders(); + + void omitEndingLineFeed(); + +public: // overridden from Writer + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; + +private: + void writeValue(const Value& value); + + JSONCPP_STRING document_; + bool yamlCompatibilityEnabled_; + bool dropNullPlaceholders_; + bool omitEndingLineFeed_; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +/** \brief Writes a Value in JSON format in a + *human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + *line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + *types, + * and all the values fit on one lines, then print the array on a single + *line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + *#CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API + StyledWriter : public Writer { +public: + StyledWriter(); + ~StyledWriter() JSONCPP_OVERRIDE {} + +public: // overridden from Writer + /** \brief Serialize a Value in JSON format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultilineArray(const Value& value); + void pushValue(const JSONCPP_STRING& value); + void writeIndent(); + void writeWithIndent(const JSONCPP_STRING& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + static bool hasCommentForValue(const Value& value); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + JSONCPP_STRING document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + unsigned int indentSize_; + bool addChildValues_; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +/** \brief Writes a Value in JSON format in a + human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + types, + * and all the values fit on one lines, then print the array on a single + line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + #CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API + StyledStreamWriter { +public: + /** + * \param indentation Each level will be indented by this amount extra. + */ + StyledStreamWriter(const JSONCPP_STRING& indentation = "\t"); + ~StyledStreamWriter() {} + +public: + /** \brief Serialize a Value in JSON format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not + * return a value. + */ + void write(JSONCPP_OSTREAM& out, const Value& root); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultilineArray(const Value& value); + void pushValue(const JSONCPP_STRING& value); + void writeIndent(); + void writeWithIndent(const JSONCPP_STRING& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + static bool hasCommentForValue(const Value& value); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + JSONCPP_OSTREAM* document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; + bool addChildValues_ : 1; + bool indented_ : 1; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(JSON_HAS_INT64) +JSONCPP_STRING JSON_API valueToString(Int value); +JSONCPP_STRING JSON_API valueToString(UInt value); +#endif // if defined(JSON_HAS_INT64) +JSONCPP_STRING JSON_API valueToString(LargestInt value); +JSONCPP_STRING JSON_API valueToString(LargestUInt value); +JSONCPP_STRING JSON_API +valueToString(double value, + unsigned int precision = Value::defaultRealPrecision, + PrecisionType precisionType = PrecisionType::significantDigits); +JSONCPP_STRING JSON_API valueToString(bool value); +JSONCPP_STRING JSON_API valueToQuotedString(const char* value); + +/// \brief Output using the StyledStreamWriter. +/// \see Json::operator>>() +JSON_API JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM&, const Value& root); + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_WRITER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/assertions.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED +#define CPPTL_JSON_ASSERTIONS_H_INCLUDED + +#include +#include + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +/** It should not be possible for a maliciously designed file to + * cause an abort() or seg-fault, so these macros are used only + * for pre-condition violations and internal logic errors. + */ +#if JSON_USE_EXCEPTION + +// @todo <= add detail about condition in exception +#define JSON_ASSERT(condition) \ + { \ + if (!(condition)) { \ + Json::throwLogicError("assert json failed"); \ + } \ + } + +#define JSON_FAIL_MESSAGE(message) \ + { \ + JSONCPP_OSTRINGSTREAM oss; \ + oss << message; \ + Json::throwLogicError(oss.str()); \ + abort(); \ + } + +#else // JSON_USE_EXCEPTION + +#define JSON_ASSERT(condition) assert(condition) + +// The call to assert() will show the failure message in debug builds. In +// release builds we abort, for a core-dump or debugger. +#define JSON_FAIL_MESSAGE(message) \ + { \ + JSONCPP_OSTRINGSTREAM oss; \ + oss << message; \ + assert(false && oss.str().c_str()); \ + abort(); \ + } + +#endif + +#define JSON_ASSERT_MESSAGE(condition, message) \ + if (!(condition)) { \ + JSON_FAIL_MESSAGE(message); \ + } + +#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/assertions.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_AMALGAMATED_H_INCLUDED diff --git a/ConfigModule/src/ConfigBase.cpp b/ConfigModule/src/ConfigBase.cpp new file mode 100644 index 0000000..e3aa899 --- /dev/null +++ b/ConfigModule/src/ConfigBase.cpp @@ -0,0 +1,30 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:50:00 + * @LastEditTime: 2025-09-11 18:42:03 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/src/CamDeal.cpp + */ +#include "ConfigBase.h" +#include "ConfigInstance.h" +#include "ConfigManager.h" + +std::shared_ptr ConfigBase::GetInstance() +{ + std::shared_ptr pInstance = std::make_shared(); + return pInstance; +} +bool compareBylay(const RegionConfigST &a, const RegionConfigST &b) +{ + return a.basicInfo.lay < b.basicInfo.lay; +} +ConfigManagerBase *ConfigManagerBase::m_pInstance = nullptr; +ConfigManagerBase *ConfigManagerBase::GetInstance() +{ + if (!m_pInstance) + { + m_pInstance = new ConfigManager(); + } + return m_pInstance; +} \ No newline at end of file diff --git a/ConfigModule/src/ConfigInstance.cpp b/ConfigModule/src/ConfigInstance.cpp new file mode 100644 index 0000000..9bb6884 --- /dev/null +++ b/ConfigModule/src/ConfigInstance.cpp @@ -0,0 +1,223 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:50:00 + * @LastEditTime: 2025-09-13 18:52:55 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/src/CamDeal.cpp + */ +#include "ConfigInstance.h" + +ConfigInstance::ConfigInstance() +{ + m_ErrorValue = ERROR_Type_Ok; + m_nCurIdx = 0; +} + +ConfigInstance::~ConfigInstance() +{ +} + +int ConfigInstance::GetConfigIdx() +{ + std::lock_guard lock(mtx_GetIdx); + int reidx = m_nCurIdx; + if (reidx < 0) + { + reidx = 0; + } + m_nCurIdx++; + if (m_nCurIdx >= MAX_USER_COUNT) + { + m_nCurIdx = MAX_USER_COUNT - 1; + } + + return reidx; +} + +bool ConfigInstance::GetConfigUpdataStatus(int nConfigType, int nidx) +{ + std::lock_guard lock(mutex_status); + + if (nConfigType >= 0 && nConfigType < ConfigType_Count && nidx >= 0 && nidx < MAX_USER_COUNT) + { + m_ErrorValue = ERROR_Type_Ok; + bool status = m_USER_ConfigUpdataStatusList[nConfigType][nidx]; + m_USER_ConfigUpdataStatusList[nConfigType][nidx] = false; + return status; + } + m_ErrorValue = ERROR_Type_ConfigType; + return false; +} + +int ConfigInstance::GetConfig(int nConfigType, void *pconfig) +{ + if (nConfigType >= 0 && nConfigType < ConfigType_Count) + { + } + else + { + m_ErrorValue = ERROR_Type_ConfigType; + return m_ErrorValue; + } + AnalysisyConfigST *p = (AnalysisyConfigST *)pconfig; + CheckConfigST *p1 = (CheckConfigST *)pconfig; + ImageInfo *pimg = (ImageInfo *)pconfig; + switch (nConfigType) + { + case ConfigType_Analysisy_Common_XL: + p->copy(m_AnalysisyConfig); + break; + case ConfigType_Check_XL: + p1->copy(m_CheckConfig); + break; + case ConfigType_Image_In: + pimg->copy(m_CheckConfig.Srcimg_in); + break; + case ConfigType_Image_out: + pimg->copy(m_CheckConfig.resultimg_out); + break; + } + + m_ErrorValue = ERROR_Type_Ok; + return 0; +} + +int ConfigInstance::UpdateConfig(void *pconfig, int nConfigType) +{ + + m_ErrorValue = ERROR_Type_Ok; + return 0; +} + +int ConfigInstance::UpdateJSONConfig(void *pconfig, int nConfigType) +{ + if (pconfig == NULL) + { + m_ErrorValue = ERROR_Type_JsonNull; + return m_ErrorValue; + } + if (nConfigType < 0 || nConfigType >= ConfigType_Count) + { + m_ErrorValue = ERROR_Type_ConfigType; + return m_ErrorValue; + } + + Json::Value *pJsonConfig = (Json::Value *)pconfig; + switch (nConfigType) + { + case ConfigType_Analysisy_Common_XL: + Updata_analysis(*pJsonConfig); + /* code */ + break; + case ConfigType_Check_XL: + /* code */ + Updata_Check(*pJsonConfig); + break; + default: + break; + } + + // getchar(); + m_ErrorValue = ERROR_Type_Ok; + return 0; +} + +std::string ConfigInstance::GetVersion() +{ + m_ErrorValue = ERROR_Type_Ok; + return std::string(); +} + +std::string ConfigInstance::GetErrorInfo() +{ + return ERROR_TYPE_Names[m_ErrorValue]; +} + +int ConfigInstance::Updata_analysis(Json::Value json_value) +{ + + // std::cout << json_value << std::endl; + CommonParamJson configJson; + configJson.toObjectFromValue(json_value); + CommonParamST config; + configJson.GetConfig(config); + + // printf("------config.skuName %s \n", config.skuName.c_str()); + + // 解析成对应的 参数 + CommonParamToCheckConfigJson tp; + tp.toObjectFromValue(config.value); + + tp.GetConfig(m_AnalysisyConfig.commonCheckConfig); + m_AnalysisyConfig.strSkuName = config.skuName; + + int img_W = 0; + int img_H = 0; + + // for (int i = 0; i < m_AnalysisyConfig.commonCheckConfig.nodeConfigArr.size(); i++) + // { + // if (i == 0) + // { + // img_W = m_AnalysisyConfig.commonCheckConfig.nodeConfigArr.at(i).nodebasicConfog.img_width; + // img_H = m_AnalysisyConfig.commonCheckConfig.nodeConfigArr.at(i).nodebasicConfog.img_height; + // } + // m_AnalysisyConfig.commonCheckConfig.nodeConfigArr.at(i).ToMaskImg(); + // std::string strpath = "mask_" + std::to_string(i) + ".jpg"; + // if (!m_AnalysisyConfig.commonCheckConfig.nodeConfigArr.at(i).mask.empty()) + // { + // cv::imwrite(strpath, m_AnalysisyConfig.commonCheckConfig.nodeConfigArr.at(i).mask); + // } + // } + + // 解析成对应的 参数 + ChannelFuntonConfigJson jxjason; + jxjason.toObjectFromValue(config.value); + + jxjason.GetConfig(m_AnalysisyConfig.checkFunction); + for (int i = 0; i < m_AnalysisyConfig.checkFunction.channelFunctionArr.size(); i++) + { + m_AnalysisyConfig.checkFunction.channelFunctionArr.at(i).function.f_ShieldRegion.ToMaskImg(img_W, img_H); + m_AnalysisyConfig.checkFunction.channelFunctionArr.at(i).function.f_EdgeROI.ToMaskImg(img_W, img_H); + m_AnalysisyConfig.checkFunction.channelFunctionArr.at(i).function.f_Image_Align.ToMaskImg(img_W, img_H); + } + + BaseFuntonConfigJson basefjason; + basefjason.toObjectFromValue(config.value); + + basefjason.GetConfig(m_AnalysisyConfig.baseFunction); + + // m_AnalysisyConfig.checkFunction.print("------------ChannelFunction---------------"); + // getchar(); + + // 更新所有状态 + SetStatus(ConfigType_Analysisy_Common_XL); + m_ErrorValue = ERROR_Type_Ok; + return 0; +} + +int ConfigInstance::Updata_Check(Json::Value json_value) +{ + std::cout << json_value << std::endl; + + // 解析成对应的 参数 + CheckConfigJson tp; + tp.toObjectFromValue(json_value); + tp.GetConfig(m_CheckConfig); + // 更新所有状态 + SetStatus(ConfigType_Check_XL); + + m_ErrorValue = ERROR_Type_Ok; + return 0; +} + +int ConfigInstance::SetStatus(int nConfigType) +{ + std::lock_guard lock(mutex_status); + for (int i = 0; i < MAX_USER_COUNT; i++) + { + m_USER_ConfigUpdataStatusList[nConfigType][i] = true; + } + m_ErrorValue = ERROR_Type_Ok; + return 0; +} diff --git a/ConfigModule/src/ConfigManager.cpp b/ConfigModule/src/ConfigManager.cpp new file mode 100644 index 0000000..af3d0cf --- /dev/null +++ b/ConfigModule/src/ConfigManager.cpp @@ -0,0 +1,222 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:50:00 + * @LastEditTime: 2025-09-11 22:03:50 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/src/CamDeal.cpp + */ + +#include "ConfigManager.h" +#include +#include "ConfigBase.h" +#include "../../AlgorithmModule/include/ImgCheckConfig.h" +ConfigManager::ConfigManager() +{ + m_strConfigRootPath = ""; +} + +ConfigManager::~ConfigManager() +{ +} + +std::vector QX_Result_Names = + { + "OK", + "aotudian", + "other", + "line", + "zangwu", + "edge", + "ymhs", + "dianzhuang", + "posun", + "xianwei", + "shuizi", + "danban", + "fuchen", + }; +std::vector QX_Result_Code = + { + "P0000", + "MA507", + "MA508", + "MA506", + "MA504", + "MA503", + "MA502", + "MA505", + "MA501", + "P0001", + "P0002", + "P0003", + "P0004", +}; + +int ReadFlawCodeConfig(std::string json_path) +{ + m_FlawCodeList.erase(m_FlawCodeList.begin(), m_FlawCodeList.end()); + std::string strPath = json_path; + printf("ReadFlawCodeConfig path %s\n", strPath.c_str()); + Json::CharReaderBuilder builder; + builder["collectComments"] = true; + Json::Value root; + std::string err; + std::ifstream ifs(strPath); + if (!ifs.is_open()) + { + printf("error:file is open\n"); + return 0; + } + if (!Json::parseFromStream(builder, ifs, &root, &err)) + { + printf("error:parseFromStream\n"); + return 0; + } + + for (int i = 0; i < root.size(); i++) + { + // printf("Node idx %d /%d \n", i, root.size()); + + ReadFlawCode tem; + tem.flaw_name = root[i]["zh_name"].asString(); + tem.flaw_code = root[i]["en_name"].asString(); + string desc = root[i]["desc"].asString(); + { + + std::istringstream stream(desc); + std::string token; + + // 使用 getline 按照分号分割 + while (std::getline(stream, token, ';')) + { + tem.config_flaw_name.push_back(token); + } + } + m_FlawCodeList.push_back(tem); + } + for(int i = 0; i < m_FlawCodeList.size(); i++) + { + if(i >= QX_Result_Names.size()) { + QX_Result_Names.push_back(m_FlawCodeList.at(i).flaw_name); + QX_Result_Code.push_back(m_FlawCodeList.at(i).flaw_code); + } + else + { + QX_Result_Names.at(i) = m_FlawCodeList.at(i).flaw_name; + QX_Result_Code.at(i) = m_FlawCodeList.at(i).flaw_code; + } + + } + return 0; +} + +int ConfigManager::LoadParamConfig(std::shared_ptr &Config, std::string strConfigPath) +{ + Json::Reader json_reader; + Json::Value json_value; + std::ifstream infile(strConfigPath, ios::binary); + printf("Analysis_Config_path========== %s \n", strConfigPath.c_str()); + // getchar(); + if (infile.is_open()) + { + if (json_reader.parse(infile, json_value)) + { + + Config->UpdateJSONConfig((void *)&json_value, ConfigType_Analysisy_Common_XL); + + // printf("m_pConfig ConfigType_Analysisy_Common_XL %s\n", Config->GetErrorInfo().c_str()); + } + else + { + printf("****%s fail \n", strConfigPath.c_str()); + } + } + else + { + printf("****%s fail \n", strConfigPath.c_str()); + infile.close(); + return 1; + } + infile.close(); + + return 0; +} +int ConfigManager::LoadAnalysisConfig(std::string strConfigPath) +{ + m_strConfigRootPath = strConfigPath; + int re = UpdateConfig(); + return re; +} + +std::string ConfigManager::GetJsonPath() +{ + return m_strConfigRootPath; +} + +int ConfigManager::UpdateConfig() +{ + string defect_list_file = GetJsonPath(); + if (defect_list_file == "") { + defect_list_file = "/var/aidlux/efs/model/defect_list.json"; + } + else{ + defect_list_file += "/defect_list.json"; + } + ReadFlawCodeConfig(defect_list_file); + bool bFileName = false; + // std::regex pattern(R"(param_[0-9]\.json)"); + std::regex pattern(R"(param_(\d+|left|right)\.json)"); + if (!fs::exists(m_strConfigRootPath)) + { + std::cerr << "目录不存在: " << m_strConfigRootPath << std::endl; + return 1; + } + // Config_instances_.clear(); + for (const auto &entry : fs::directory_iterator(m_strConfigRootPath)) + { + if (entry.is_regular_file()) + { + std::string filename = entry.path().filename().string(); + if (std::regex_match(filename, pattern)) + { + bFileName = true; + std::cout << "匹配文件: " << entry.path() << std::endl; + std::shared_ptr temConfig = ConfigBase::GetInstance(); + int re = LoadParamConfig(temConfig, entry.path()); + if (re != 0) + { + continue; + } + + AnalysisyConfigST p; + temConfig->GetConfig(ConfigType_Analysisy_Common_XL, &p); + printf("********* CamearName %s\n", p.commonCheckConfig.baseConfig.strCamearName.c_str()); + if (p.commonCheckConfig.baseConfig.strCamearName == "") + { + printf("Error >>>> camear Name is empty \n"); + continue; + } + auto it = Config_instances_.find(p.commonCheckConfig.baseConfig.strCamearName); + if (it != Config_instances_.end() && it->second) { + LoadParamConfig(it->second, entry.path()); + } else { + Config_instances_[p.commonCheckConfig.baseConfig.strCamearName] = temConfig; + } + } + } + else + { + std::cerr << "config error 2: " << m_strConfigRootPath << std::endl; + } + } + if(!bFileName){ + cout << "Error >>>> no param_x.json file !!!!!!!!!!!!\n"; + return 2; + } + return 0; +} +int ConfigManager::GetConfig(int nConfigType, void *pconfig) +{ + return 0; +} \ No newline at end of file diff --git a/ConfigModule/src/Define.cpp b/ConfigModule/src/Define.cpp new file mode 100644 index 0000000..234ceef --- /dev/null +++ b/ConfigModule/src/Define.cpp @@ -0,0 +1 @@ +#include "Define.h" diff --git a/ConfigModule/src/JsonConfig.cpp b/ConfigModule/src/JsonConfig.cpp new file mode 100644 index 0000000..c296c79 --- /dev/null +++ b/ConfigModule/src/JsonConfig.cpp @@ -0,0 +1,1447 @@ +#include "JsonConfig.h" + +Json::Value CommonParamJson::toJsonValue() +{ + return Json::Value(); +} + +void CommonParamJson::toObjectFromValue(Json::Value root) +{ + _config.image = root["image"].asString(); + _config.skuName = root["sku_name"].asString(); + _config.value = root["value"].asString(); +} + +int CommonParamJson::GetConfig(CommonParamST &config) +{ + config.copy(_config); + return 0; +} + +Json::Value CommonParamToCheckConfigJson::toJsonValue() +{ + return Json::Value(); +} + +// 读取和图片相关的参数 +void CommonParamToCheckConfigJson::toObjectFromValue(Json::Value root) +{ + + auto strJson = root.asString(); + Json::CharReaderBuilder builder; + std::unique_ptr reader(builder.newCharReader()); + Json::Value rootvalue; + std::string err; + // std::cout << strJson << std::endl; + auto nSize = strJson.size(); + if (reader->parse(strJson.c_str(), strJson.c_str() + nSize, &rootvalue, &err)) + { + + // 和节点无关参数提取 + { + auto value = rootvalue["base"]; + // std::cout << value << std::endl; + // getchar(); + if (value.isObject()) + { + _config.baseConfig.image_widht = value["image_widht"].asInt(); + _config.baseConfig.Image_height = value["Image_height"].asInt(); + _config.baseConfig.bDrawShieldRoi = value["bDrawShieldRoi"].asBool(); + _config.baseConfig.bDrawPreRoi = value["Draw_PreROI"].asBool(); + _config.baseConfig.bShield_ZF = value["bShield_ZF"].asBool(); + _config.baseConfig.fUP_IOU = value["UP_IOU"].asFloat(); + _config.baseConfig.strCamName = value["cameraCode"].asString(); + _config.baseConfig.strCamearName = value["cameraCode"].asString(); + _config.baseConfig.bCal_ImageScale = value["bImageScale_Cal"].asBool(); + _config.baseConfig.Product_Size_Width_mm = value["Product_Size_W"].asFloat(); + _config.baseConfig.Product_Size_Height_mm = value["Product_Size_H"].asFloat(); + _config.baseConfig.fImage_Scale_x = value["Image_Scale_X"].asFloat(); + _config.baseConfig.fImage_Scale_y = value["Image_Scale_Y"].asFloat(); + if (value["Density_R"]) + { + _config.baseConfig.density_R_mm = value["Density_R"].asFloat(); + if (_config.baseConfig.density_R_mm <= 0 || _config.baseConfig.density_R_mm > 99999) + { + _config.baseConfig.density_R_mm = 5; + } + } + } + } + // 读取每个节点的参数 + { + auto value_node = rootvalue["node"]; + // 读取每个节点的参数 + for (int i = 0; i < value_node.size(); i++) + { + printf("Node idx %d /%d \n", i, value_node.size()); + + CommonConfigNodeST tem_node; + // 和节点相关基础参数 + { + auto value_node_base = value_node[i]["node_base"]; + // std::cout << value_node_base << std::endl; + + if (value_node_base.isObject()) + { + + tem_node.nodebasicConfog.calss_conf = value_node_base["class_conf"].asFloat(); + tem_node.nodebasicConfog.calss_area = value_node_base["Class_AreaT"].asFloat(); + + // tem_node.nodebasicConfog.print("nodebasicConfog"); + } + } + + // 读取当前节点下 的每张图片 一般只读第一张图 + { + auto value_node_imgs = value_node[i]["node_images"]; + + if (value_node_imgs.size() > 0) + { + int img_idx = 0; + tem_node.nodebasicConfog.img_width = value_node_imgs[img_idx]["width"].asInt(); + tem_node.nodebasicConfog.img_height = value_node_imgs[img_idx]["height"].asInt(); + + auto value_node_imgs_region = value_node_imgs[img_idx]["params"]; + // printf("tem_node.img_height %d, tem_node.img_width %d region num %d\n", + // tem_node.nodebasicConfog.img_height, + // tem_node.nodebasicConfog.img_width, + // value_node_imgs_region.size()); + + for (int region_idx = 0; region_idx < value_node_imgs_region.size(); region_idx++) + { + // printf("region idx %d /%d \n", region_idx, value_node_imgs_region.size()); + + RegionConfigST temRegion; + temRegion.buse = true; + // 1、读取基本参数 + { + auto value_node_imgs_region_base = value_node_imgs_region[region_idx]; + // std::cout< tem_node.nodebasicConfog.img_width) + { + p.x = tem_node.nodebasicConfog.img_width; + } + if (p.y < 0) + { + p.y = 0; + } + if (p.y > tem_node.nodebasicConfog.img_height) + { + p.y = tem_node.nodebasicConfog.img_height; + } + temRegion.basicInfo.pointArry.emplace_back(p); + } + } + } + // 3、读取检测参数 和存图参数 + for (int ParamType_idx = 0; ParamType_idx < ANALYSIS_TYPE_COUNT; ParamType_idx++) + { + if (temRegion.basicInfo.type == 1) + { + continue; + } + + // int param_type = ParamType_idx; + + auto value_node_imgs_region_Check_Param = value_node_imgs_region[region_idx][ANALYSIS_TYPE_Names[ParamType_idx]]; + + if (value_node_imgs_region_Check_Param.isObject()) + { + + for (Json::ValueIterator iter = value_node_imgs_region_Check_Param.begin(); iter != value_node_imgs_region_Check_Param.end(); iter++) + { + CheckConfig_Regions_Param tem_paramValue; + + // const char *name = iter.memberName(); + std::string name = iter.name(); // 新方法,推荐使用 + tem_paramValue.param_name = name; + auto value_node_imgs_region_Check_Param_value = value_node_imgs_region_Check_Param[name]; + + if (value_node_imgs_region_Check_Param_value.isArray()) + { + + for (int idx = 0; idx < value_node_imgs_region_Check_Param_value.size(); idx++) + { + + AandEParam temparam; + temparam.bEnable = value_node_imgs_region_Check_Param_value[idx]["state"].asBool(); + temparam.bOk = value_node_imgs_region_Check_Param_value[idx]["bOK"].asBool(); + if (value_node_imgs_region_Check_Param_value[idx]["area"]) + { + temparam.area = value_node_imgs_region_Check_Param_value[idx]["area"].asFloat(); + } + if (value_node_imgs_region_Check_Param_value[idx]["area_max"]) + { + temparam.area_max = value_node_imgs_region_Check_Param_value[idx]["area_max"].asFloat(); + } + if (value_node_imgs_region_Check_Param_value[idx]["energy"]) + { + temparam.energy = value_node_imgs_region_Check_Param_value[idx]["energy"].asFloat(); + } + + if (value_node_imgs_region_Check_Param_value[idx]["hj"]) + { + temparam.hj = value_node_imgs_region_Check_Param_value[idx]["hj"].asFloat(); + } + + if (value_node_imgs_region_Check_Param_value[idx]["length"]) + { + temparam.length = value_node_imgs_region_Check_Param_value[idx]["length"].asFloat(); + } + + if (value_node_imgs_region_Check_Param_value[idx]["breadth"]) + { + temparam.breadth = value_node_imgs_region_Check_Param_value[idx]["breadth"].asFloat(); + } + + if (value_node_imgs_region_Check_Param_value[idx]["num"]) + { + temparam.num = value_node_imgs_region_Check_Param_value[idx]["num"].asInt(); + } + + if (value_node_imgs_region_Check_Param_value[idx]["dis"]) + { + temparam.dis = value_node_imgs_region_Check_Param_value[idx]["dis"].asFloat(); + } + if (value_node_imgs_region_Check_Param_value[idx]["density"]) + { + temparam.density = value_node_imgs_region_Check_Param_value[idx]["density"].asFloat(); + } + std::string str = ANALYSIS_TYPE_Names[ParamType_idx] + " " + name + " " + std::to_string(idx); + // temparam.print(str); + tem_paramValue.addParam(temparam); + } + } + temRegion.checkConfig_Regions_type[ParamType_idx].checkConfig_Regions_Param.push_back(tem_paramValue); + } + } + } + + tem_node.regionConfigArr.push_back(temRegion); + } + } + } + + _config.nodeConfigArr.push_back(tem_node); + } + } + } + else + { + printf("--- ******error json*** \n"); + } +} +int CommonParamToCheckConfigJson::GetConfig(CommonCheckConfigST &config) +{ + config.copy(_config); + return 0; +} + +Json::Value CheckConfigJson::toJsonValue() +{ + return Json::Value(); +} + +void CheckConfigJson::toObjectFromValue(Json::Value root) +{ + { + auto value = root["AI_Model_Path"]; + if (value.isObject()) + { + + _config.modelConfig.defect_model_path = value["defect"].asString(); + _config.modelConfig.YX_1_model_path = value["yx_1"].asString(); + _config.modelConfig.YX_2_model_path = value["yx_2"].asString(); + _config.modelConfig.class_model_path = value["class"].asString(); + _config.modelConfig.defect_wtb_model_path = value["defect_wtb"].asString(); + _config.modelConfig.zf_model_path = value["defect_zf"].asString(); + _config.modelConfig.UP_model_path = value["defect_UP"].asString(); + _config.modelConfig.class_L0_model_path = value["class_L0"].asString(); + _config.modelConfig.class_L255_model_path = value["class_L255"].asString(); + if (value["defect_chess"]) + { + _config.modelConfig.defect_chess_model_path = value["defect_chess"].asString(); + } + + // 1024dyy + std::cout << "_config.modelConfig.defect_model_path=" << _config.modelConfig.defect_model_path << std::endl; // 1126dyy-add + std::cout << "_config.modelConfig.YX_1_model_path=" << _config.modelConfig.YX_1_model_path << std::endl; // 1126dyy + std::cout << "_config.modelConfig.YX_2_model_path=" << _config.modelConfig.YX_2_model_path << std::endl; // 1126dyy + std::cout << "_config.modelConfig.class_model_path=" << _config.modelConfig.class_model_path << std::endl; // 1126dyy-add + std::cout << "_config.modelConfig.defect_wtb_model_path=" << _config.modelConfig.defect_wtb_model_path << std::endl; // 1126dyy-add + std::cout << "_config.modelConfig.defect_chess_model_path=" << _config.modelConfig.defect_chess_model_path << std::endl; // 1126dyy-add + std::cout << "_config.modelConfig.zf_model_path=" << _config.modelConfig.zf_model_path << std::endl; // 1126dyy-add + std::cout << "_config.modelConfig.UP_model_path=" << _config.modelConfig.UP_model_path << std::endl; // 1126dyy-add + std::cout << "_config.modelConfig.class_L0_model_path=" << _config.modelConfig.class_L0_model_path << std::endl; // 1126dyy-add + std::cout << "_config.modelConfig.class_L255_model_path=" << _config.modelConfig.class_L255_model_path << std::endl; // 1126dyy-add + } + } + + { + auto value = root["image_preprocess_param"]; + if (value.isObject()) + { + auto arr = value["crop_roi"]; + if (arr.isArray()) + { + _config.preDealImgConfig.cutRoi.x = arr[0].asInt(); + _config.preDealImgConfig.cutRoi.y = arr[1].asInt(); + _config.preDealImgConfig.cutRoi.width = arr[2].asInt(); + _config.preDealImgConfig.cutRoi.height = arr[3].asInt(); + } + _config.preDealImgConfig.bresize = value["resize"].asBool(); + _config.preDealImgConfig.bInAI_ImgFflip = value["ai_input_image_flip"].asBool(); + _config.preDealImgConfig.bOutAI_ImgFflip = value["ai_output_image_flip"].asBool(); + } + } + { + auto value = root["Camer_param"]; + if (value.isObject()) + { + + _config.camConfig.fscale_x = value["scale_x"].asFloat(); + _config.camConfig.fscale_y = value["scale_y"].asFloat(); + + std::cout << "_config.camConfig.fscale_x=" << _config.camConfig.fscale_x << std::endl; + std::cout << "_config.camConfig.fscale_y=" << _config.camConfig.fscale_y << std::endl; + } + } + { + auto value = root["image_Info"]; + if (value.isObject()) + { + + _config.resultimg_out.width = value["result_image_width"].asInt(); + _config.resultimg_out.height = value["result_image_height"].asInt(); + _config.resultimg_out.channels = value["result_image_channels"].asInt(); + + _config.resultimg_out.print("resultimg_out"); + + _config.Srcimg_in.width = value["src_image_width"].asInt(); + _config.Srcimg_in.height = value["src_image_height"].asInt(); + _config.Srcimg_in.channels = value["src_image_channels"].asInt(); + + _config.Srcimg_in.print("Srcimg_in"); + } + } +} +int CheckConfigJson::GetConfig(CheckConfigST &config) +{ + config.copy(_config); + return 0; +} + +Json::Value ChannelFuntonConfigJson::toJsonValue() +{ + return Json::Value(); +} + +void ChannelFuntonConfigJson::toObjectFromValue(Json::Value root) +{ + auto strJson = root.asString(); + Json::CharReaderBuilder builder; + std::unique_ptr reader(builder.newCharReader()); + Json::Value rootvalue; + std::string err; + // std::cout << "ChannelFuntonConfigJson" << std::endl + // << std::endl + // << std::endl; + // std::cout << strJson << std::endl; + auto nSize = strJson.size(); + + if (reader->parse(strJson.c_str(), strJson.c_str() + nSize, &rootvalue, &err)) + { + // 和节点无关参数提取 + + auto value = rootvalue["checkData"]; + if (value.isArray()) + { + for (int idx = 0; idx < value.size(); idx++) + { + ChannelCheckFunction channel; + if (value[idx]["panelCode"]) + { + channel.strChannelName = value[idx]["panelCode"].asString(); + } + else + { + continue; + } + GetFunction(value[idx]["checkItem"], channel.function); + + // up 特殊处理 + if (channel.strChannelName == "Up-Particle" && channel.function.f_BaseDet.bOpen) + { + channel.function.f_OnlyBLob.bOpen = true; + } + + // channel.print("channel"); + // getchar(); + _config.channelFunctionArr.push_back(channel); + } + // _config.print("channelFunction"); + } + } +} + +int ChannelFuntonConfigJson::GetConfig(ALLChannelCheckFunction &config) +{ + config.copy(_config); + return 0; +} + +int ChannelFuntonConfigJson::GetFunction(Json::Value value, CheckFunction &function) +{ + // std::cout << value << std::endl; + + if (value.isArray()) + { + for (int i = 0; i < value.size(); i++) + { + + std::string strCode = value[i]["itemCode"].asString(); + // std::cout << strCode << std::endl; + // 读取UP 过滤功能 + if ("QX_Detect" == strCode) + { + auto value_f = value[i]; + // std::cout << value_f << std::endl; + function.f_BaseDet.bOpen = value_f["isOpen"].asBool(); + if (function.f_BaseDet.bOpen) + { + /* code */ + + if (value_f["form"]["Base_Det"]["AI_Model"]) + { + function.f_BaseDet.strAIMode = value_f["form"]["Base_Det"]["AI_Model"].asString(); + } + + auto value_qx = value_f["form"]["Base_Det"]["Det_QX"]; + if (value_qx.isArray()) + { + for (int idx = 0; idx < value_qx.size(); idx++) + { + std::string qx = value_qx[idx].asString(); + function.f_BaseDet.DetQXList.push_back(qx); + } + } + } + else + { + function.f_BaseDet.Init(); + } + } + // 读取UP 过滤功能 + if ("UP_Use" == strCode) + { + auto value_f = value[i]; + // std::cout << value_f << std::endl; + function.f_UseUpQX.bOpen = value_f["isOpen"].asBool(); + if (function.f_UseUpQX.bOpen) + { + /* code */ + + if (value_f["form"]["UP_QX_Filter"]["IOU"]) + { + function.f_UseUpQX.fIOU = value_f["form"]["UP_QX_Filter"]["IOU"].asFloat(); + } + } + else + { + function.f_UseUpQX.Init(); + } + // function.f_UseUpQX.print("UpQX"); + } + if ("AI_Class" == strCode) + { + auto value_f = value[i]; + // std::cout << value_f << std::endl; + function.f_AIQX.bOpen = value_f["isOpen"].asBool(); + if (function.f_AIQX.bOpen) + { + /* code */ + + if (value_f["form"]["AI_QX"]["POLToWhitePOL"]) + { + function.f_AIQX.bPOLToWhitePOL = value_f["form"]["AI_QX"]["POLToWhitePOL"].asBool(); + } + if (value_f["form"]["AI_QX"]["ALLToChess"]) + { + function.f_AIQX.bAllToChess = value_f["form"]["AI_QX"]["ALLToChess"].asBool(); + } + } + else + { + function.f_AIQX.Init(); + } + + // function.f_UseUpQX.print("UpQX"); + } + if ("YX_Detect" == strCode) + { + auto value_f = value[i]; + // std::cout << value_f << std::endl; + function.f_YXDet.bOpen = value_f["isOpen"].asBool(); + if (value_f["form"]["YX_Det"]["AI_Model"]) + { + function.f_YXDet.strModle = value_f["form"]["YX_Det"]["AI_Model"].asString(); + } + + // function.f_UseUpQX.print("UpQX"); + } + if ("LD_Detect" == strCode) + { + auto value_f = value[i]; + // std::cout << value_f << std::endl; + function.f_LDConfig.bOpen = value_f["isOpen"].asBool(); + if (function.f_LDConfig.bOpen) + { + /* code */ + + if (value_f["form"]["LD_Det"]["bUseDP"]) + { + function.f_LDConfig.bUseDP = value_f["form"]["LD_Det"]["bUseDP"].asBool(); + } + if (value_f["form"]["LD_Det"]["WTB_LD"]) + { + function.f_LDConfig.bWTBLD = value_f["form"]["LD_Det"]["WTB_LD"].asBool(); + } + if (value_f["form"]["LD_Det"]["HS_LD"]) + { + function.f_LDConfig.bHSLD = value_f["form"]["LD_Det"]["HS_LD"].asBool(); + } + + if (value_f["form"]["LD_Det"]["DP_IOU"]) + { + function.f_LDConfig.fDP_IOU = value_f["form"]["LD_Det"]["DP_IOU"].asFloat(); + } + } + else + { + function.f_LDConfig.Init(); + } + + // function.f_UseUpQX.print("UpQX"); + } + if ("Det_Cell" == strCode) + { + auto value_f = value[i]; + // std::cout << value_f << std::endl; + function.f_Det127Cell.bOpen = value_f["isOpen"].asBool(); + } + // 大缺陷检测 + if ("BigQX_Detect" == strCode) + { + auto value_f = value[i]; + // std::cout << value_f << std::endl; + function.f_Big_QX.bOpen = value_f["isOpen"].asBool(); + if (value_f["form"]["SingleConfig"]["Area"]) + { + function.f_Big_QX.Single_Area = value_f["form"]["SingleConfig"]["Area"].asFloat(); + } + if (value_f["form"]["SingleConfig"]["HJ"]) + { + function.f_Big_QX.Single_HJ = value_f["form"]["SingleConfig"]["HJ"].asInt(); + } + if (value_f["form"]["SingleConfig"]["Length"]) + { + function.f_Big_QX.Single_Len = value_f["form"]["SingleConfig"]["Length"].asFloat(); + } + if (value_f["form"]["Sum_Area"]["Blob_Num"]) + { + function.f_Big_QX.Sum_blob_Num = value_f["form"]["Sum_Area"]["Blob_Num"].asInt(); + } + if (value_f["form"]["Sum_Area"]["Area_Sum"]) + { + function.f_Big_QX.Sum_Area = value_f["form"]["Sum_Area"]["Area_Sum"].asFloat(); + } + } + // 屏蔽区域 + if ("ShieldRegion" == strCode) + { + auto value_f = value[i]; + // std::cout << value_f << std::endl; + function.f_ShieldRegion.bOpen = value_f["isOpen"].asBool(); + if (function.f_ShieldRegion.bOpen) + { + /* code */ + + if (value_f["form"]["ShieldRegionConfig"]["bDraw"]) + { + function.f_ShieldRegion.bDraw = value_f["form"]["ShieldRegionConfig"]["bDraw"].asBool(); + } + { + auto region_coord = value_f["form"]["ShieldRegionConfig"]["region_1"]; + if (region_coord.isArray()) + { + for (int idx = 0; idx < region_coord.size(); idx++) + { + cv::Point p; + p.x = region_coord[idx][0].asInt(); + p.y = region_coord[idx][1].asInt(); + function.f_ShieldRegion.pointArry1.emplace_back(p); + } + } + // printf(" pointArry1 size %d \n", function.f_ShieldRegion.pointArry1.size()); + } + + { + auto region_coord = value_f["form"]["ShieldRegionConfig"]["region_2"]; + if (region_coord.isArray()) + { + for (int idx = 0; idx < region_coord.size(); idx++) + { + cv::Point p; + p.x = region_coord[idx][0].asInt(); + p.y = region_coord[idx][1].asInt(); + function.f_ShieldRegion.pointArry2.emplace_back(p); + } + } + // printf(" pointArry2 size %d \n", function.f_ShieldRegion.pointArry2.size()); + } + { + auto region_coord = value_f["form"]["ShieldRegionConfig"]["region_3"]; + if (region_coord.isArray()) + { + for (int idx = 0; idx < region_coord.size(); idx++) + { + cv::Point p; + p.x = region_coord[idx][0].asInt(); + p.y = region_coord[idx][1].asInt(); + function.f_ShieldRegion.pointArry3.emplace_back(p); + } + } + // printf(" pointArry3 size %d \n", function.f_ShieldRegion.pointArry3.size()); + } + { + auto region_coord = value_f["form"]["ShieldRegionConfig"]["region_4"]; + if (region_coord.isArray()) + { + for (int idx = 0; idx < region_coord.size(); idx++) + { + cv::Point p; + p.x = region_coord[idx][0].asInt(); + p.y = region_coord[idx][1].asInt(); + function.f_ShieldRegion.pointArry4.emplace_back(p); + } + } + // printf(" pointArry4 size %d \n", function.f_ShieldRegion.pointArry4.size()); + } + { + auto region_coord = value_f["form"]["ShieldRegionConfig"]["region_5"]; + if (region_coord.isArray()) + { + for (int idx = 0; idx < region_coord.size(); idx++) + { + cv::Point p; + p.x = region_coord[idx][0].asInt(); + p.y = region_coord[idx][1].asInt(); + function.f_ShieldRegion.pointArry5.emplace_back(p); + } + } + // printf(" pointArry5 size %d \n", function.f_ShieldRegion.pointArry5.size()); + } + } + else + { + function.f_ShieldRegion.Init(); + } + } + // 边缘roi + if ("Crop_ROI" == strCode) + { + auto value_f = value[i]; + // std::cout << value_f << std::endl; + function.f_EdgeROI.bOpen = value_f["isOpen"].asBool(); + if (function.f_EdgeROI.bOpen) + { + /* code */ + + if (value_f["form"]["ROI_Config"]["Use_DrawROI"]) + { + function.f_EdgeROI.Use_DrawROI = value_f["form"]["ROI_Config"]["Use_DrawROI"].asBool(); + } + if (value_f["form"]["ROI_Config"]["Use_DetEdge"]) + { + function.f_EdgeROI.Use_DetEdge = value_f["form"]["ROI_Config"]["Use_DetEdge"].asBool(); + } + if (value_f["form"]["ROI_Config"]["Use_AIEdge"]) + { + function.f_EdgeROI.Use_AIEdge = value_f["form"]["ROI_Config"]["Use_AIEdge"].asBool(); + } + if (value_f["form"]["ROI_Config"]["AI_Fail_UseDraw"]) + { + function.f_EdgeROI.AI_Fail_UseDraw = value_f["form"]["ROI_Config"]["AI_Fail_UseDraw"].asBool(); + } + if (value_f["form"]["ROI_Config"]["threshold_value"]) + { + function.f_EdgeROI.threshold_value = value_f["form"]["ROI_Config"]["threshold_value"].asInt(); + } + if (value_f["form"]["ROI_Config"]["threshold_value"]) + { + function.f_EdgeROI.AI_Erode_Size = value_f["form"]["ROI_Config"]["AI_Erode_Size"].asInt(); + } + { + auto region_coord = value_f["form"]["ROI_Config"]["ROI"]; + if (region_coord.isArray()) + { + for (int idx = 0; idx < region_coord.size(); idx++) + { + cv::Point p; + p.x = region_coord[idx][0].asInt(); + p.y = region_coord[idx][1].asInt(); + function.f_EdgeROI.pointArry1.emplace_back(p); + } + } + // printf(" pointArry1 size %d \n", function.f_ShieldRegion.pointArry1.size()); + } + } + else + { + function.f_EdgeROI.Init(); + } + } + // 边缘roi + if ("Image_Align_T" == strCode) + { + auto value_f = value[i]; + // std::cout << value_f << std::endl; + function.f_Image_Align.bOpen = value_f["isOpen"].asBool(); + if (function.f_Image_Align.bOpen) + { + /* code */ + + { + auto region_coord = value_f["form"]["Align_Config"]["Edge_TZ"]; + if (region_coord.isArray()) + { + for (int idx = 0; idx < region_coord.size(); idx++) + { + cv::Point p; + p.x = region_coord[idx][0].asInt(); + p.y = region_coord[idx][1].asInt(); + function.f_Image_Align.pointArry1.emplace_back(p); + } + } + // printf(" pointArry1 size %d \n", function.f_ShieldRegion.pointArry1.size()); + } + { + auto region_roi = value_f["form"]["Align_Config"]["Search_ROI"]; + + { + if (region_roi["x"]) + { + function.f_Image_Align.search_Roi.x = region_roi["x"].asInt(); + } + if (region_roi["y"]) + { + function.f_Image_Align.search_Roi.y = region_roi["y"].asInt(); + } + if (region_roi["width"]) + { + function.f_Image_Align.search_Roi.width = region_roi["width"].asInt(); + } + if (region_roi["height"]) + { + function.f_Image_Align.search_Roi.height = region_roi["height"].asInt(); + } + } + // printf(" pointArry1 size %d \n", function.f_ShieldRegion.pointArry1.size()); + } + { + auto Kernel_roi = value_f["form"]["Align_Config"]["Kernel_ROI"]; + + { + if (Kernel_roi["x"]) + { + function.f_Image_Align.feature_Roi.x = Kernel_roi["x"].asInt(); + } + if (Kernel_roi["y"]) + { + function.f_Image_Align.feature_Roi.y = Kernel_roi["y"].asInt(); + } + if (Kernel_roi["width"]) + { + function.f_Image_Align.feature_Roi.width = Kernel_roi["width"].asInt(); + } + if (Kernel_roi["height"]) + { + function.f_Image_Align.feature_Roi.height = Kernel_roi["height"].asInt(); + } + } + // printf(" pointArry1 size %d \n", function.f_ShieldRegion.pointArry1.size()); + } + { + auto crop_roi = value_f["form"]["Align_Config"]["Crop_ROI"]; + + { + if (crop_roi["x"]) + { + function.f_Image_Align.Crop_Roi.x = crop_roi["x"].asInt(); + } + if (crop_roi["y"]) + { + function.f_Image_Align.Crop_Roi.y = crop_roi["y"].asInt(); + } + if (crop_roi["width"]) + { + function.f_Image_Align.Crop_Roi.width = crop_roi["width"].asInt(); + } + if (crop_roi["height"]) + { + function.f_Image_Align.Crop_Roi.height = crop_roi["height"].asInt(); + } + } + // printf(" pointArry1 size %d \n", function.f_ShieldRegion.pointArry1.size()); + } + { + if (value_f["form"]["Align_Config"]["bDraw"]) + { + function.f_Image_Align.bDraw = value_f["form"]["Align_Config"]["bDraw"].asBool(); + } + } + { + if (value_f["form"]["Align_Config"]["Score"]) + { + float fs = value_f["form"]["Align_Config"]["Score"].asFloat(); + if (fs > 0.01 && fs <= 1) + { + function.f_Image_Align.fscore = fs; + } + } + } + if (value_f["form"]["Align_Config"]["UseType"]) + { + std::string str = value_f["form"]["Align_Config"]["UseType"].asString(); + if (str == "Use") + { + function.f_Image_Align.runType = Function_Image_Align::type_Use; + } + else if (str == "Test") + { + function.f_Image_Align.runType = Function_Image_Align::type_Test; + } + else + { + function.f_Image_Align.runType = Function_Image_Align::type_Use; + } + } + } + else + { + function.f_Image_Align.Init(); + } + } + // 缺pol 检测 + if ("LackPOL_Det" == strCode) + { + auto value_f = value[i]; + // std::cout << value_f << std::endl; + function.f_Dectect_LackPol.bOpen = value_f["isOpen"].asBool(); + } + + // 二次分类检测 + if ("Second_Det" == strCode) + { + auto value_f = value[i]; + // std::cout << value_f << std::endl; + function.f_SecondDetect.bOpen = value_f["isOpen"].asBool(); + if (function.f_SecondDetect.bOpen) + { + if (value_f["form"]["Andain_Config"]["Open_Area"]) + { + function.f_SecondDetect.andian_Open_area = value_f["form"]["Andain_Config"]["Open_Area"].asBool(); + } + if (value_f["form"]["Andain_Config"]["Open_Len"]) + { + function.f_SecondDetect.andian_Open_len = value_f["form"]["Andain_Config"]["Open_Len"].asBool(); + } + if (value_f["form"]["Andain_Config"]["Area_min"]) + { + function.f_SecondDetect.andian_area_min = value_f["form"]["Andain_Config"]["Area_min"].asFloat(); + } + if (value_f["form"]["Andain_Config"]["Area_max"]) + { + function.f_SecondDetect.andian_area_max = value_f["form"]["Andain_Config"]["Area_max"].asFloat(); + } + if (value_f["form"]["Andain_Config"]["SaveProcessImg"]) + { + function.f_SecondDetect.andian_saveProcessImg = value_f["form"]["Andain_Config"]["SaveProcessImg"].asBool(); + } + + if (value_f["form"]["POL_Config"]["Open_Area"]) + { + function.f_SecondDetect.pol_Open_area = value_f["form"]["POL_Config"]["Open_Area"].asBool(); + } + if (value_f["form"]["POL_Config"]["Open_Len"]) + { + function.f_SecondDetect.pol_Open_len = value_f["form"]["POL_Config"]["Open_Len"].asBool(); + } + if (value_f["form"]["POL_Config"]["Area_min"]) + { + function.f_SecondDetect.pol_area_min = value_f["form"]["POL_Config"]["Area_min"].asFloat(); + } + if (value_f["form"]["POL_Config"]["Area_max"]) + { + function.f_SecondDetect.pol_area_max = value_f["form"]["POL_Config"]["Area_max"].asFloat(); + } + if (value_f["form"]["POL_Config"]["Open_Single_Check"]) + { + function.f_SecondDetect.pol_open_SingleCheck = value_f["form"]["POL_Config"]["Open_Single_Check"].asBool(); + } + if (value_f["form"]["POL_Config"]["Open_Create_Pol"]) + { + function.f_SecondDetect.pol_open_Create = value_f["form"]["POL_Config"]["Open_Create_Pol"].asBool(); + } + if (value_f["form"]["POL_Config"]["SaveProcessImg"]) + { + function.f_SecondDetect.pol_saveProcessImg = value_f["form"]["POL_Config"]["SaveProcessImg"].asBool(); + } + } + else + { + function.f_SecondDetect.Init(); + } + // getchar(); + } + // 暗点检测 + if ("AD_Check" == strCode) + { + auto value_f = value[i]; + // std::cout << value_f << std::endl; + function.f_AD_Check.bOpen = value_f["isOpen"].asBool(); + if (function.f_AD_Check.bOpen) + { + if (value_f["form"]["AD_S_Standard"]["AD_3S_Area"]) + { + function.f_AD_Check.S_standard_3s.area = value_f["form"]["AD_S_Standard"]["AD_3S_Area"].asFloat(); + } + if (value_f["form"]["AD_S_Standard"]["AD_3S_Len"]) + { + function.f_AD_Check.S_standard_3s.len = value_f["form"]["AD_S_Standard"]["AD_3S_Len"].asFloat(); + } + + if (value_f["form"]["AD_S_Standard"]["AD_2S_Area"]) + { + function.f_AD_Check.S_standard_2s.area = value_f["form"]["AD_S_Standard"]["AD_2S_Area"].asFloat(); + } + if (value_f["form"]["AD_S_Standard"]["AD_2S_Len"]) + { + function.f_AD_Check.S_standard_2s.len = value_f["form"]["AD_S_Standard"]["AD_2S_Len"].asFloat(); + } + + if (value_f["form"]["AD_S_Standard"]["AD_1S_Area"]) + { + function.f_AD_Check.S_standard_1s.area = value_f["form"]["AD_S_Standard"]["AD_1S_Area"].asFloat(); + } + if (value_f["form"]["AD_S_Standard"]["AD_1S_Len"]) + { + function.f_AD_Check.S_standard_1s.len = value_f["form"]["AD_S_Standard"]["AD_1S_Len"].asFloat(); + } + + if (value_f["form"]["AD_Check_Num"]["Open"]) + { + function.f_AD_Check.analysis_num.bOpen = value_f["form"]["AD_Check_Num"]["Open"].asBool(); + } + if (value_f["form"]["AD_Check_Num"]["Num"]) + { + function.f_AD_Check.analysis_num.numT = value_f["form"]["AD_Check_Num"]["Num"].asInt(); + } + + if (value_f["form"]["AD_Check_Dis"]["Open"]) + { + function.f_AD_Check.analysis_dis.bOpen = value_f["form"]["AD_Check_Dis"]["Open"].asBool(); + } + if (value_f["form"]["AD_Check_Dis"]["Dis"]) + { + function.f_AD_Check.analysis_dis.disT = value_f["form"]["AD_Check_Dis"]["Dis"].asFloat(); + } + + if (value_f["form"]["AD_Check_S"]["Open"]) + { + function.f_AD_Check.analysis_s.bOpen = value_f["form"]["AD_Check_S"]["Open"].asBool(); + } + + if (value_f["form"]["AD_Check_S"]["S_value"]) + { + function.f_AD_Check.analysis_s.Check_s_Value = value_f["form"]["AD_Check_S"]["S_value"].asInt(); + } + if (value_f["form"]["AD_Check_S"]["NG_3s"]) + { + function.f_AD_Check.analysis_s.NG_3s = value_f["form"]["AD_Check_S"]["NG_3s"].asBool(); + } + if (value_f["form"]["AD_Check_S"]["Num"]) + { + function.f_AD_Check.analysis_s.Check_s_Num = value_f["form"]["AD_Check_S"]["Num"].asInt(); + } + } + else + { + function.f_AD_Check.Init(); + } + // getchar(); + } + // 异物检测 + if ("POL_Cam" == strCode) + { + auto value_f = value[i]; + // std::cout << value_f << std::endl; + function.f_POL_Check.bOpen = value_f["isOpen"].asBool(); + if (function.f_POL_Check.bOpen) + { + if (value_f["form"]["AnalysisConfig"]["Num"]) + { + function.f_POL_Check.numT = value_f["form"]["AnalysisConfig"]["Num"].asInt(); + } + } + else + { + function.f_POL_Check.Init(); + } + // getchar(); + } + } + } + return 0; +} + +Json::Value BaseFuntonConfigJson::toJsonValue() +{ + return Json::Value(); +} + +void BaseFuntonConfigJson::toObjectFromValue(Json::Value root) +{ + auto strJson = root.asString(); + Json::CharReaderBuilder builder; + std::unique_ptr reader(builder.newCharReader()); + Json::Value rootvalue; + std::string err; + // std::cout << "BaseFuntonConfigJson" << std::endl + // << std::endl + // << std::endl; + // std::cout << strJson << std::endl; + auto nSize = strJson.size(); + + if (reader->parse(strJson.c_str(), strJson.c_str() + nSize, &rootvalue, &err)) + { + // 和节点无关参数提取 + + auto value = rootvalue["baseCheckData"]; + // printf("\n\n\n"); + // std::cout << value << std::endl; + // getchar(); + if (value.isArray()) + { + for (int idx = 0; idx < value.size(); idx++) + { + GetFunction(value[idx]); + } + // _config.print("channelFunction"); + } + } +} + +int BaseFuntonConfigJson::GetConfig(BaseCheckFunction &config) +{ + config.copy(_config); + return 0; +} + +int BaseFuntonConfigJson::GetFunction(Json::Value value) +{ + + // std::cout << value << std::endl; + + std::string strCode = value["itemCode"].asString(); + // std::cout << strCode << std::endl; + // 读取UP 过滤功能 + if ("AlignDet" == strCode) + { + auto value_f = value; + // std::cout << value_f << std::endl; + // getchar(); + _config.markLine.bOpen = value_f["isOpen"].asBool(); + if (_config.markLine.bOpen) + { + + { + auto crop_roi = value_f["form"]["ALign_Config"]["Product_ROI"]; + // 2、读取区域点 + { + auto value_region = value_f["form"]["ALign_Config"]["Product_ROI"]; + if (value_region.isArray()) + { + for (int idx = 0; idx < value_region.size(); idx++) + { + cv::Point p; + p.x = value_region[idx][0].asInt(); + p.y = value_region[idx][1].asInt(); + + _config.markLine.region.emplace_back(p); + } + if (_config.markLine.region.size() > 0) + { + _config.markLine.productROI = boundingRect(_config.markLine.region); + } + } + } + + // printf(" pointArry1 size %d \n", function.f_ShieldRegion.pointArry1.size()); + } + if (value_f["form"]["ALign_Config"]["bDraw"]) + { + _config.markLine.bDraw = value_f["form"]["ALign_Config"]["bDraw"].asBool(); + } + if (value_f["form"]["ALign_Config"]["badapt_region"]) + { + _config.markLine.badapt_region = value_f["form"]["ALign_Config"]["badapt_region"].asBool(); + } + { + auto value_circl = value_f["form"]["ALign_Config"]["mark_1_Local"]["path"]; + if (value_circl.isArray()) + { + + if (value_circl[0][0]) + { + _config.markLine.mark_local_1.x = value_circl[0][0].asInt(); + } + if (value_circl[0][1]) + { + _config.markLine.mark_local_1.y = value_circl[0][1].asInt(); + } + } + } + { + auto value_circl = value_f["form"]["ALign_Config"]["mark_2_Local"]["path"]; + if (value_circl.isArray()) + { + + if (value_circl[0][0]) + { + _config.markLine.mark_local_2.x = value_circl[0][0].asInt(); + } + if (value_circl[0][1]) + { + _config.markLine.mark_local_2.y = value_circl[0][1].asInt(); + } + } + } + // _config.markLine.print("dfe"); + // getchar(); + } + else + { + _config.markLine.Init(); + } + } + if ("Edge_QX_Detect" == strCode) + { + auto value_f = value; + // std::cout << value_f << std::endl; + // getchar(); + _config.edgeDet.bOpen = value_f["isOpen"].asBool(); + if (_config.edgeDet.bOpen) + { + + if (value_f["form"]["Search_Config"]["Search_threshold"]) + { + _config.edgeDet.Search_threshold = value_f["form"]["Search_Config"]["Search_threshold"].asInt(); + } + if (value_f["form"]["Detect_Config"]["Det_threshold"]) + { + _config.edgeDet.Det_threshold = value_f["form"]["Detect_Config"]["Det_threshold"].asInt(); + } + if (value_f["form"]["Detect_Config"]["Det_Range"]) + { + _config.edgeDet.Det_Range = value_f["form"]["Detect_Config"]["Det_Range"].asInt(); + } + + if (value_f["form"]["Detect_Config"]["QX_Widht_min"]) + { + _config.edgeDet.QX_Widht_min = value_f["form"]["Detect_Config"]["QX_Widht_min"].asInt(); + } + + if (value_f["form"]["Detect_Config"]["QX_Widht_max"]) + { + _config.edgeDet.QX_Widht_max = value_f["form"]["Detect_Config"]["QX_Widht_max"].asInt(); + } + + if (value_f["form"]["Detect_Config"]["QX_Height_min"]) + { + _config.edgeDet.QX_Height_min = value_f["form"]["Detect_Config"]["QX_Height_min"].asInt(); + } + + if (value_f["form"]["Detect_Config"]["QX_Height_max"]) + { + _config.edgeDet.QX_Height_max = value_f["form"]["Detect_Config"]["QX_Height_max"].asInt(); + } + + ///============================================ + + if (value_f["form"]["Jiao_Config"]["LU_Jiao"]) + { + _config.edgeDet.queJiao_LU_Open = value_f["form"]["Jiao_Config"]["LU_Jiao"].asBool(); + } + if (value_f["form"]["Jiao_Config"]["RU_Jiao"]) + { + _config.edgeDet.queJiao_RU_Open = value_f["form"]["Jiao_Config"]["RU_Jiao"].asBool(); + } + + if (value_f["form"]["Jiao_Config"]["LD_Jiao"]) + { + _config.edgeDet.queJiao_LD_Open = value_f["form"]["Jiao_Config"]["LD_Jiao"].asBool(); + } + + if (value_f["form"]["Jiao_Config"]["RD_Jiao"]) + { + _config.edgeDet.queJiao_RD_Open = value_f["form"]["Jiao_Config"]["RD_Jiao"].asBool(); + } + + if (value_f["form"]["Jiao_Config"]["Jiao_Width"]) + { + _config.edgeDet.queJiao_width = value_f["form"]["Jiao_Config"]["Jiao_Width"].asInt(); + } + + if (value_f["form"]["Jiao_Config"]["Jiao_Height"]) + { + _config.edgeDet.queJiao_height = value_f["form"]["Jiao_Config"]["Jiao_Height"].asInt(); + } + + if (value_f["form"]["Draw_Config"]["Open"]) + { + _config.edgeDet.bDrawRoi = value_f["form"]["Draw_Config"]["Open"].asBool(); + } + + // 2、读取区域点 + { + auto value_region = value_f["form"]["Draw_Config"]["Edge_ROI"]; + if (value_region.isArray()) + { + for (int idx = 0; idx < value_region.size(); idx++) + { + cv::Point p; + p.x = value_region[idx][0].asInt(); + p.y = value_region[idx][1].asInt(); + + _config.edgeDet.region.emplace_back(p); + } + if (_config.edgeDet.region.size() > 0) + { + _config.edgeDet.draw_ROI = boundingRect(_config.edgeDet.region); + } + } + } + if (value_f["form"]["otherConfig"]["bDrawResult"]) + { + _config.edgeDet.bDrawResult = value_f["form"]["otherConfig"]["bDrawResult"].asBool(); + } + } + else + { + _config.edgeDet.Init(); + } + // _config.edgeDet.print("edgeDet"); + // getchar(); + } + if ("Det_Image_Save" == strCode) + { + auto value_f = value; + // std::cout << value_f << std::endl; + // getchar(); + _config.saveImg.bOpen = value_f["isOpen"].asBool(); + if (_config.saveImg.bOpen) + { + + if (value_f["form"]["SaveImg_Config"]["Mark_Save"]) + { + _config.saveImg.bSaveMarkImg = value_f["form"]["SaveImg_Config"]["Mark_Save"].asBool(); + } + if (value_f["form"]["SaveImg_Config"]["Cls_Save"]) + { + _config.saveImg.bSaveClsImg = value_f["form"]["SaveImg_Config"]["Cls_Save"].asBool(); + } + if (value_f["form"]["SaveImg_Config"]["Align_Big_Save"]) + { + _config.saveImg.bSaveAlginImg = value_f["form"]["SaveImg_Config"]["Align_Big_Save"].asBool(); + } + } + else + { + _config.saveImg.Init(); + } + // _config.edgeDet.print("edgeDet"); + // getchar(); + } + if ("Big_NG" == strCode) + { + auto value_f = value; + // std::cout << value_f << std::endl; + // getchar(); + _config.bigNG.bOpen = value_f["isOpen"].asBool(); + if (_config.bigNG.bOpen) + { + if (value_f["form"]["aotudian"]["open"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_aotudian].bOpen = value_f["form"]["aotudian"]["open"].asBool(); + } + if (value_f["form"]["aotudian"]["Area"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_aotudian].fArea = value_f["form"]["aotudian"]["Area"].asFloat(); + } + _config.bigNG.qx[CONFIG_QX_NAME_cell_aotudian].strname = "aotudian"; + + if (value_f["form"]["other"]["open"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_other].bOpen = value_f["form"]["other"]["open"].asBool(); + } + if (value_f["form"]["other"]["Area"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_other].fArea = value_f["form"]["other"]["Area"].asFloat(); + } + _config.bigNG.qx[CONFIG_QX_NAME_cell_other].strname = "other"; + + if (value_f["form"]["line"]["open"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_line].bOpen = value_f["form"]["line"]["open"].asBool(); + } + if (value_f["form"]["line"]["Area"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_line].fArea = value_f["form"]["line"]["Area"].asFloat(); + } + _config.bigNG.qx[CONFIG_QX_NAME_cell_line].strname = "line"; + + if (value_f["form"]["zangwu"]["open"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_zangwu].bOpen = value_f["form"]["zangwu"]["open"].asBool(); + } + if (value_f["form"]["zangwu"]["Area"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_zangwu].fArea = value_f["form"]["zangwu"]["Area"].asFloat(); + } + _config.bigNG.qx[CONFIG_QX_NAME_cell_zangwu].strname = "zangwu"; + + if (value_f["form"]["edge"]["open"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_edge].bOpen = value_f["form"]["edge"]["open"].asBool(); + } + if (value_f["form"]["edge"]["Area"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_edge].fArea = value_f["form"]["edge"]["Area"].asFloat(); + } + _config.bigNG.qx[CONFIG_QX_NAME_cell_edge].strname = "edge"; + + if (value_f["form"]["ymhs"]["open"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_ymhs].bOpen = value_f["form"]["ymhs"]["open"].asBool(); + } + if (value_f["form"]["ymhs"]["Area"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_ymhs].fArea = value_f["form"]["ymhs"]["Area"].asFloat(); + } + _config.bigNG.qx[CONFIG_QX_NAME_cell_ymhs].strname = "ymhs"; + + if (value_f["form"]["dianzhuang"]["open"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_dianzhuang].bOpen = value_f["form"]["dianzhuang"]["open"].asBool(); + } + if (value_f["form"]["dianzhuang"]["Area"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_dianzhuang].fArea = value_f["form"]["dianzhuang"]["Area"].asFloat(); + } + _config.bigNG.qx[CONFIG_QX_NAME_cell_dianzhuang].strname = "dianzhuang"; + + if (value_f["form"]["posun"]["open"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_posun].bOpen = value_f["form"]["posun"]["open"].asBool(); + } + if (value_f["form"]["posun"]["Area"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_posun].fArea = value_f["form"]["posun"]["Area"].asFloat(); + } + _config.bigNG.qx[CONFIG_QX_NAME_cell_posun].strname = "posun"; + + if (value_f["form"]["xianwei"]["open"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_xianwei].bOpen = value_f["form"]["xianwei"]["open"].asBool(); + } + if (value_f["form"]["xianwei"]["Area"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_xianwei].fArea = value_f["form"]["xianwei"]["Area"].asFloat(); + } + _config.bigNG.qx[CONFIG_QX_NAME_cell_xianwei].strname = "xianwei"; + + if (value_f["form"]["shuizi"]["open"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_shuizi].bOpen = value_f["form"]["shuizi"]["open"].asBool(); + } + if (value_f["form"]["shuizi"]["Area"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_shuizi].fArea = value_f["form"]["shuizi"]["Area"].asFloat(); + } + _config.bigNG.qx[CONFIG_QX_NAME_cell_shuizi].strname = "shuizi"; + + if (value_f["form"]["danban"]["open"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_danban].bOpen = value_f["form"]["danban"]["open"].asBool(); + } + if (value_f["form"]["danban"]["Area"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_danban].fArea = value_f["form"]["danban"]["Area"].asFloat(); + } + _config.bigNG.qx[CONFIG_QX_NAME_cell_danban].strname = "danban"; + + if (value_f["form"]["fuchen"]["open"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_fuchen].bOpen = value_f["form"]["fuchen"]["open"].asBool(); + } + if (value_f["form"]["fuchen"]["Area"]) + { + _config.bigNG.qx[CONFIG_QX_NAME_cell_fuchen].fArea = value_f["form"]["fuchen"]["Area"].asFloat(); + } + _config.bigNG.qx[CONFIG_QX_NAME_cell_fuchen].strname = "fuchen"; + } + else + { + _config.bigNG.Init(); + } + // _config.edgeDet.print("edgeDet"); + // getchar(); + } + return 0; +} diff --git a/ConfigModule/src/JsonCoversion.cpp b/ConfigModule/src/JsonCoversion.cpp new file mode 100644 index 0000000..13c1478 --- /dev/null +++ b/ConfigModule/src/JsonCoversion.cpp @@ -0,0 +1,35 @@ +#include "JsonCoversion.h" + +JsonCoversion::JsonCoversion() +{ + //ctor +} + +JsonCoversion::~JsonCoversion() +{ + //dtor +} +string JsonCoversion::toJson() +{ + toJsonValue(); + + std::unique_ptr jsonWriter(writerBuilder.newStreamWriter()); + std::ostringstream os; + std::string jsonStr; + jsonWriter->write(root,&os); + jsonStr = os.str(); + return jsonStr; +} + +void JsonCoversion::toObject(string & strBuf) +{ + std::unique_ptr const jsonReader(readerBuilder.newCharReader()); + + JSONCPP_STRING errs; + bool res = jsonReader->parse(strBuf.c_str(), strBuf.c_str()+strBuf.length(), &root, &errs); + if (!res || !errs.empty()) + { + std::cout << "parseJson err. " << errs << std::endl; + } + toObjectFromValue(root); +} diff --git a/ConfigModule/src/jsoncpp.cpp b/ConfigModule/src/jsoncpp.cpp new file mode 100644 index 0000000..ebd3aa5 --- /dev/null +++ b/ConfigModule/src/jsoncpp.cpp @@ -0,0 +1,5467 @@ +/// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + + +#include "json/json.h" +#ifndef JSON_IS_AMALGAMATION +#error "Compile with -I PATH_TO_JSON_DIRECTORY" +#endif + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_tool.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED +#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include +#endif + +// Also support old flag NO_LOCALE_SUPPORT +#ifdef NO_LOCALE_SUPPORT +#define JSONCPP_NO_LOCALE_SUPPORT +#endif + +#ifndef JSONCPP_NO_LOCALE_SUPPORT +#include +#endif + +/* This header provides common string manipulation support, such as UTF-8, + * portable conversion from/to string... + * + * It is an internal header that must not be exposed. + */ + +namespace Json { +static inline char getDecimalPoint() { +#ifdef JSONCPP_NO_LOCALE_SUPPORT + return '\0'; +#else + struct lconv* lc = localeconv(); + return lc ? *(lc->decimal_point) : '\0'; +#endif +} + +/// Converts a unicode code-point to UTF-8. +static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) { + JSONCPP_STRING result; + + // based on description from http://en.wikipedia.org/wiki/UTF-8 + + if (cp <= 0x7f) { + result.resize(1); + result[0] = static_cast(cp); + } else if (cp <= 0x7FF) { + result.resize(2); + result[1] = static_cast(0x80 | (0x3f & cp)); + result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); + } else if (cp <= 0xFFFF) { + result.resize(3); + result[2] = static_cast(0x80 | (0x3f & cp)); + result[1] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[0] = static_cast(0xE0 | (0xf & (cp >> 12))); + } else if (cp <= 0x10FFFF) { + result.resize(4); + result[3] = static_cast(0x80 | (0x3f & cp)); + result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); + } + // printf("-----------------111--cp %d-------\n",cp); + if ((cp >= 0x4E00 && cp <= 0x9FA5) || (cp >= 0xF00 && cp <= 0xFA2D) ) + { + + wchar_t src[2] = { 0 }; + char dest[5] = { 0 }; + src[0] = static_cast(cp); + std::string curLocale = setlocale(LC_ALL,NULL); + setlocale(LC_ALL,"chs"); + wcstombs(dest, src, 5); + result = dest; + setlocale(LC_ALL, curLocale.c_str()); + } + + + return result; +} + +enum { + /// Constant that specify the size of the buffer that must be passed to + /// uintToString. + uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 +}; + +// Defines a char buffer for use with uintToString(). +typedef char UIntToStringBuffer[uintToStringBufferSize]; + +/** Converts an unsigned integer to string. + * @param value Unsigned integer to convert to string + * @param current Input/Output string buffer. + * Must have at least uintToStringBufferSize chars free. + */ +static inline void uintToString(LargestUInt value, char*& current) { + *--current = 0; + do { + *--current = static_cast(value % 10U + static_cast('0')); + value /= 10; + } while (value != 0); +} + +/** Change ',' to '.' everywhere in buffer. + * + * We had a sophisticated way, but it did not work in WinCE. + * @see https://github.com/open-source-parsers/jsoncpp/pull/9 + */ +template Iter fixNumericLocale(Iter begin, Iter end) { + for (; begin != end; ++begin) { + if (*begin == ',') { + *begin = '.'; + } + } + return begin; +} + +template void fixNumericLocaleInput(Iter begin, Iter end) { + char decimalPoint = getDecimalPoint(); + if (decimalPoint == '\0' || decimalPoint == '.') { + return; + } + for (; begin != end; ++begin) { + if (*begin == '.') { + *begin = decimalPoint; + } + } +} + +/** + * Return iterator that would be the new end of the range [begin,end), if we + * were to delete zeros in the end of string, but not the last zero before '.'. + */ +template Iter fixZerosInTheEnd(Iter begin, Iter end) { + for (; begin != end; --end) { + if (*(end - 1) != '0') { + return end; + } + // Don't delete the last zero before the decimal point. + if (begin != (end - 1) && *(end - 2) == '.') { + return end; + } + } + return end; +} + +} // namespace Json + +#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_tool.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors +// Copyright (C) 2016 InfoTeCS JSC. All rights reserved. +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include "json_tool.h" +#include +#include +#include +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include +#include +#include + +#if __cplusplus >= 201103L +#include + +#if !defined(snprintf) +#define snprintf std::snprintf +#endif + +#if !defined(sscanf) +#define sscanf std::sscanf +#endif +#else +#include + +#if defined(_MSC_VER) +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 +#if !defined(snprintf) +#define snprintf _snprintf +#endif +#endif +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile +// time to change the stack limit +#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) +#define JSONCPP_DEPRECATED_STACK_LIMIT 1000 +#endif + +static size_t const stackLimit_g = + JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue() + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr CharReaderPtr; +#else +typedef std::auto_ptr CharReaderPtr; +#endif + +// Implementation of class Features +// //////////////////////////////// + +Features::Features() + : allowComments_(true), strictRoot_(false), + allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} + +Features Features::all() { return Features(); } + +Features Features::strictMode() { + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + features.allowDroppedNullPlaceholders_ = false; + features.allowNumericKeys_ = false; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + +bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) { + for (; begin < end; ++begin) + if (*begin == '\n' || *begin == '\r') + return true; + return false; +} + +// Class Reader +// ////////////////////////////////////////////////////////////////// + +Reader::Reader() + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(Features::all()), + collectComments_() {} + +Reader::Reader(const Features& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(features), collectComments_() { +} + +bool Reader::parse(const std::string& document, + Value& root, + bool collectComments) { + document_.assign(document.begin(), document.end()); + const char* begin = document_.c_str(); + const char* end = begin + document_.length(); + return parse(begin, end, root, collectComments); +} + +bool Reader::parse(std::istream& is, Value& root, bool collectComments) { + // std::istream_iterator begin(is); + // std::istream_iterator end; + // Those would allow streamed input from a file, if parse() were a + // template function. + + // Since JSONCPP_STRING is reference-counted, this at least does not + // create an extra copy. + JSONCPP_STRING doc; + std::getline(is, doc, (char)EOF); + return parse(doc.data(), doc.data() + doc.size(), root, collectComments); +} + +bool Reader::parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments) { + if (!features_.allowComments_) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_.clear(); + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) { + if (!root.isArray() && !root.isObject()) { + // Set error location to start of doc, ideally should be first token found + // in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( + "A valid JSON document must be either an array or an object value.", + token); + return false; + } + } + return successful; +} + +bool Reader::readValue() { + // readValue() may call itself only if it calls readObject() or ReadArray(). + // These methods execute nodes_.push() just before and nodes_.pop)() just + // after calling readValue(). parse() executes one nodes_.push(), so > instead + // of >=. + if (nodes_.size() > stackLimit_g) + throwRuntimeError("Exceeded stackLimit in readValue()."); + + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_.clear(); + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenFalse: { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenNull: { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // Else, fall through... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + return successful; +} + +void Reader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool Reader::readToken(Token& token) { + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + token.type_ = tokenNumber; + readNumber(); + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + +void Reader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool Reader::match(Location pattern, int patternLength) { + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool Reader::readComment() { + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if (c == '*') + successful = readCStyleComment(); + else if (c == '/') + successful = readCppStyleComment(); + if (!successful) + return false; + + if (collectComments_) { + CommentPlacement placement = commentBefore; + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (c != '*' || !containsNewLine(commentBegin, current_)) + placement = commentAfterOnSameLine; + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin, + Reader::Location end) { + JSONCPP_STRING normalized; + normalized.reserve(static_cast(end - begin)); + Reader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void Reader::addComment(Location begin, + Location end, + CommentPlacement placement) { + assert(collectComments_); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool Reader::readCStyleComment() { + while ((current_ + 1) < end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool Reader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +void Reader::readNumber() { + const char* p = current_; + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : '\0'; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } +} + +bool Reader::readString() { + Char c = '\0'; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + +bool Reader::readObject(Token& token) { + Token tokenName; + JSONCPP_STRING name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(token.start_ - begin_); + while (readToken(tokenName)) { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + return true; + name.clear(); + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = JSONCPP_STRING(numberName.asCString()); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover("Missing ':' after object member name", colon, + tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment)) { + return addErrorAndRecover("Missing ',' or '}' in object declaration", + comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover("Missing '}' or object member name", tokenName, + tokenObjectEnd); +} + +bool Reader::readArray(Token& token) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(token.start_ - begin_); + skipSpaces(); + if (current_ != end_ && *current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } + int index = 0; + for (;;) { + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token currentToken; + // Accept Comment after last item in the array. + ok = readToken(currentToken); + while (currentToken.type_ == tokenComment && ok) { + ok = readToken(currentToken); + } + bool badTokenType = (currentToken.type_ != tokenArraySeparator && + currentToken.type_ != tokenArrayEnd); + if (!ok || badTokenType) { + return addErrorAndRecover("Missing ',' or ']' in array declaration", + currentToken, tokenArrayEnd); + } + if (currentToken.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool Reader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeNumber(Token& token, Value& decoded) { + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if (isNegative) + ++current; + // TODO: Help the compiler do the div and mod at compile time or get rid of + // them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(static_cast(c - '0')); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative && value == maxIntegerValue) + decoded = Value::minLargestInt; + else if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool Reader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + JSONCPP_STRING buffer(token.start_, token.end_); + JSONCPP_ISTRINGSTREAM is(buffer); + if (!(is >> value)) + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool Reader::decodeString(Token& token) { + JSONCPP_STRING decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) { + decoded.reserve(static_cast(token.end_ - token.start_ - 2)); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + + //printf("-->>>>>>>>>>>>>>>>>>>1>>>>>>\n"); + + while (current != end) { + Char c = *current++; + if (c == '"') + break; + else if (c == '\\') { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } break; + default: + return addError("Bad escape sequence in string", token, current); + } + } else { + decoded += c; + } + } + return true; +} + +bool Reader::decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) + return addError( + "additional six characters expected to parse unicode surrogate pair.", + token, current); + if (*(current++) == '\\' && *(current++) == 'u') { + unsigned int surrogatePair; + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } else + return false; + } else + return addError("expecting another \\u token to begin the second half of " + "a unicode surrogate pair", + token, current); + } + return true; +} + +bool Reader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& ret_unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", token, + current); + int unicode = 0; + for (int index = 0; index < 4; ++index) { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError( + "Bad unicode escape sequence in string: hexadecimal digit expected.", + token, current); + } + ret_unicode = static_cast(unicode); + return true; +} + +bool Reader::addError(const JSONCPP_STRING& message, + Token& token, + Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool Reader::recoverFromError(TokenType skipUntilToken) { + size_t const errorCount = errors_.size(); + Token skip; + for (;;) { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} + +bool Reader::addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& Reader::currentValue() { return *(nodes_.top()); } + +Reader::Char Reader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void Reader::getLocationLineAndColumn(Location location, + int& line, + int& column) const { + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) { + Char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + +JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +// Deprecated. Preserved for backward compatibility +JSONCPP_STRING Reader::getFormatedErrorMessages() const { + return getFormattedErrorMessages(); +} + +JSONCPP_STRING Reader::getFormattedErrorMessages() const { + JSONCPP_STRING formattedMessage; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); ++itError) { + const ErrorInfo& error = *itError; + formattedMessage += + "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += + "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} + +std::vector Reader::getStructuredErrors() const { + std::vector allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); ++itError) { + const ErrorInfo& error = *itError; + Reader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) { + ptrdiff_t const length = end_ - begin_; + if (value.getOffsetStart() > length || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool Reader::pushError(const Value& value, + const JSONCPP_STRING& message, + const Value& extra) { + ptrdiff_t const length = end_ - begin_; + if (value.getOffsetStart() > length || value.getOffsetLimit() > length || + extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool Reader::good() const { return !errors_.size(); } + +// exact copy of Features +class OurFeatures { +public: + static OurFeatures all(); + bool allowComments_; + bool strictRoot_; + bool allowDroppedNullPlaceholders_; + bool allowNumericKeys_; + bool allowSingleQuotes_; + bool failIfExtra_; + bool rejectDupKeys_; + bool allowSpecialFloats_; + int stackLimit_; +}; // OurFeatures + +// exact copy of Implementation of class Features +// //////////////////////////////// + +OurFeatures OurFeatures::all() { return OurFeatures(); } + +// Implementation of class Reader +// //////////////////////////////// + +// exact copy of Reader, renamed to OurReader +class OurReader { +public: + typedef char Char; + typedef const Char* Location; + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; + }; + + OurReader(OurFeatures const& features); + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + JSONCPP_STRING getFormattedErrorMessages() const; + std::vector getStructuredErrors() const; + bool pushError(const Value& value, const JSONCPP_STRING& message); + bool pushError(const Value& value, + const JSONCPP_STRING& message, + const Value& extra); + bool good() const; + +private: + OurReader(OurReader const&); // no impl + void operator=(OurReader const&); // no impl + + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenNaN, + tokenPosInf, + tokenNegInf, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + JSONCPP_STRING message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + bool readStringSingleQuote(); + bool readNumber(bool checkInf); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, JSONCPP_STRING& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool + addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + JSONCPP_STRING getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + static JSONCPP_STRING normalizeEOL(Location begin, Location end); + static bool containsNewLine(Location begin, Location end); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + JSONCPP_STRING document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + JSONCPP_STRING commentsBefore_; + + OurFeatures const features_; + bool collectComments_; +}; // OurReader + +// complete copy of Read impl, for OurReader + +bool OurReader::containsNewLine(OurReader::Location begin, + OurReader::Location end) { + for (; begin < end; ++begin) + if (*begin == '\n' || *begin == '\r') + return true; + return false; +} + +OurReader::OurReader(OurFeatures const& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(features), collectComments_() { +} + +bool OurReader::parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments) { + if (!features_.allowComments_) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_.clear(); + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (features_.failIfExtra_) { + if ((features_.strictRoot_ || token.type_ != tokenError) && + token.type_ != tokenEndOfStream) { + addError("Extra non-whitespace after JSON value.", token); + return false; + } + } + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) { + if (!root.isArray() && !root.isObject()) { + // Set error location to start of doc, ideally should be first token found + // in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( + "A valid JSON document must be either an array or an object value.", + token); + return false; + } + } + return successful; +} + +bool OurReader::readValue() { + // To preserve the old behaviour we cast size_t to int. + if (static_cast(nodes_.size()) > features_.stackLimit_) + throwRuntimeError("Exceeded stackLimit in readValue()."); + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_.clear(); + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenFalse: { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenNull: { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenNaN: { + Value v(std::numeric_limits::quiet_NaN()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenPosInf: { + Value v(std::numeric_limits::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenNegInf: { + Value v(-std::numeric_limits::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // else, fall through ... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + return successful; +} + +void OurReader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool OurReader::readToken(Token& token) { + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '\'': + if (features_.allowSingleQuotes_) { + token.type_ = tokenString; + ok = readStringSingleQuote(); + break; + } // else fall through + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + token.type_ = tokenNumber; + readNumber(false); + break; + case '-': + if (readNumber(true)) { + token.type_ = tokenNumber; + } else { + token.type_ = tokenNegInf; + ok = features_.allowSpecialFloats_ && match("nfinity", 7); + } + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case 'N': + if (features_.allowSpecialFloats_) { + token.type_ = tokenNaN; + ok = match("aN", 2); + } else { + ok = false; + } + break; + case 'I': + if (features_.allowSpecialFloats_) { + token.type_ = tokenPosInf; + ok = match("nfinity", 7); + } else { + ok = false; + } + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + +void OurReader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool OurReader::match(Location pattern, int patternLength) { + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool OurReader::readComment() { + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if (c == '*') + successful = readCStyleComment(); + else if (c == '/') + successful = readCppStyleComment(); + if (!successful) + return false; + + if (collectComments_) { + CommentPlacement placement = commentBefore; + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (c != '*' || !containsNewLine(commentBegin, current_)) + placement = commentAfterOnSameLine; + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, + OurReader::Location end) { + JSONCPP_STRING normalized; + normalized.reserve(static_cast(end - begin)); + OurReader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void OurReader::addComment(Location begin, + Location end, + CommentPlacement placement) { + assert(collectComments_); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool OurReader::readCStyleComment() { + while ((current_ + 1) < end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool OurReader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +bool OurReader::readNumber(bool checkInf) { + const char* p = current_; + if (checkInf && p != end_ && *p == 'I') { + current_ = ++p; + return false; + } + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : '\0'; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + return true; +} +bool OurReader::readString() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + +bool OurReader::readStringSingleQuote() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '\'') + break; + } + return c == '\''; +} + +bool OurReader::readObject(Token& token) { + Token tokenName; + JSONCPP_STRING name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(token.start_ - begin_); + while (readToken(tokenName)) { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + return true; + name.clear(); + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = numberName.asString(); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover("Missing ':' after object member name", colon, + tokenObjectEnd); + } + if (name.length() >= (1U << 30)) + throwRuntimeError("keylength >= 2^30"); + if (features_.rejectDupKeys_ && currentValue().isMember(name)) { + JSONCPP_STRING msg = "Duplicate key: '" + name + "'"; + return addErrorAndRecover(msg, tokenName, tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment)) { + return addErrorAndRecover("Missing ',' or '}' in object declaration", + comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover("Missing '}' or object member name", tokenName, + tokenObjectEnd); +} + +bool OurReader::readArray(Token& token) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(token.start_ - begin_); + skipSpaces(); + if (current_ != end_ && *current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } + int index = 0; + for (;;) { + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token currentToken; + // Accept Comment after last item in the array. + ok = readToken(currentToken); + while (currentToken.type_ == tokenComment && ok) { + ok = readToken(currentToken); + } + bool badTokenType = (currentToken.type_ != tokenArraySeparator && + currentToken.type_ != tokenArrayEnd); + if (!ok || badTokenType) { + return addErrorAndRecover("Missing ',' or ']' in array declaration", + currentToken, tokenArrayEnd); + } + if (currentToken.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool OurReader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeNumber(Token& token, Value& decoded) { + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if (isNegative) + ++current; + // TODO: Help the compiler do the div and mod at compile time or get rid of + // them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(-Value::minLargestInt) + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(static_cast(c - '0')); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool OurReader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + const int bufferSize = 32; + int count; + ptrdiff_t const length = token.end_ - token.start_; + + // Sanity check to avoid buffer overflow exploits. + if (length < 0) { + return addError("Unable to parse token length", token); + } + size_t const ulength = static_cast(length); + + // Avoid using a string constant for the format control string given to + // sscanf, as this can cause hard to debug crashes on OS X. See here for more + // info: + // + // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html + char format[] = "%lf"; + + if (length <= bufferSize) { + Char buffer[bufferSize + 1]; + memcpy(buffer, token.start_, ulength); + buffer[length] = 0; + fixNumericLocaleInput(buffer, buffer + length); + count = sscanf(buffer, format, &value); + } else { + JSONCPP_STRING buffer(token.start_, token.end_); + count = sscanf(buffer.c_str(), format, &value); + } + + if (count != 1) + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool OurReader::decodeString(Token& token) { + JSONCPP_STRING decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) { + decoded.reserve(static_cast(token.end_ - token.start_ - 2)); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + //printf("-->>>>>>>>>>>>>>>>>>2>>>>>>\n"); + while (current != end) { + Char c = *current++; + if (c == '"') + break; + else if (c == '\\') { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } break; + default: + return addError("Bad escape sequence in string", token, current); + } + } else { + decoded += c; + } + } + return true; +} + +bool OurReader::decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) + return addError( + "additional six characters expected to parse unicode surrogate pair.", + token, current); + if (*(current++) == '\\' && *(current++) == 'u') { + unsigned int surrogatePair; + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } else + return false; + } else + return addError("expecting another \\u token to begin the second half of " + "a unicode surrogate pair", + token, current); + } + return true; +} + +bool OurReader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& ret_unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", token, + current); + int unicode = 0; + for (int index = 0; index < 4; ++index) { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError( + "Bad unicode escape sequence in string: hexadecimal digit expected.", + token, current); + } + ret_unicode = static_cast(unicode); + return true; +} + +bool OurReader::addError(const JSONCPP_STRING& message, + Token& token, + Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool OurReader::recoverFromError(TokenType skipUntilToken) { + size_t errorCount = errors_.size(); + Token skip; + for (;;) { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} + +bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& OurReader::currentValue() { return *(nodes_.top()); } + +OurReader::Char OurReader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void OurReader::getLocationLineAndColumn(Location location, + int& line, + int& column) const { + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) { + Char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + +JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +JSONCPP_STRING OurReader::getFormattedErrorMessages() const { + JSONCPP_STRING formattedMessage; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); ++itError) { + const ErrorInfo& error = *itError; + formattedMessage += + "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += + "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} + +std::vector OurReader::getStructuredErrors() const { + std::vector allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); ++itError) { + const ErrorInfo& error = *itError; + OurReader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) { + ptrdiff_t length = end_ - begin_; + if (value.getOffsetStart() > length || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool OurReader::pushError(const Value& value, + const JSONCPP_STRING& message, + const Value& extra) { + ptrdiff_t length = end_ - begin_; + if (value.getOffsetStart() > length || value.getOffsetLimit() > length || + extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool OurReader::good() const { return !errors_.size(); } + +class OurCharReader : public CharReader { + bool const collectComments_; + OurReader reader_; + +public: + OurCharReader(bool collectComments, OurFeatures const& features) + : collectComments_(collectComments), reader_(features) {} + bool parse(char const* beginDoc, + char const* endDoc, + Value* root, + JSONCPP_STRING* errs) JSONCPP_OVERRIDE { + bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); + if (errs) { + *errs = reader_.getFormattedErrorMessages(); + } + return ok; + } +}; + +CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); } +CharReaderBuilder::~CharReaderBuilder() {} +CharReader* CharReaderBuilder::newCharReader() const { + bool collectComments = settings_["collectComments"].asBool(); + OurFeatures features = OurFeatures::all(); + features.allowComments_ = settings_["allowComments"].asBool(); + features.strictRoot_ = settings_["strictRoot"].asBool(); + features.allowDroppedNullPlaceholders_ = + settings_["allowDroppedNullPlaceholders"].asBool(); + features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); + features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); + features.stackLimit_ = settings_["stackLimit"].asInt(); + features.failIfExtra_ = settings_["failIfExtra"].asBool(); + features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); + features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); + return new OurCharReader(collectComments, features); +} +static void getValidReaderKeys(std::set* valid_keys) { + valid_keys->clear(); + valid_keys->insert("collectComments"); + valid_keys->insert("allowComments"); + valid_keys->insert("strictRoot"); + valid_keys->insert("allowDroppedNullPlaceholders"); + valid_keys->insert("allowNumericKeys"); + valid_keys->insert("allowSingleQuotes"); + valid_keys->insert("stackLimit"); + valid_keys->insert("failIfExtra"); + valid_keys->insert("rejectDupKeys"); + valid_keys->insert("allowSpecialFloats"); +} +bool CharReaderBuilder::validate(Json::Value* invalid) const { + Json::Value my_invalid; + if (!invalid) + invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set valid_keys; + getValidReaderKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + JSONCPP_STRING const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& CharReaderBuilder::operator[](JSONCPP_STRING key) { + return settings_[key]; +} +// static +void CharReaderBuilder::strictMode(Json::Value* settings) { + //! [CharReaderBuilderStrictMode] + (*settings)["allowComments"] = false; + (*settings)["strictRoot"] = true; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = true; + (*settings)["rejectDupKeys"] = true; + (*settings)["allowSpecialFloats"] = false; + //! [CharReaderBuilderStrictMode] +} +// static +void CharReaderBuilder::setDefaults(Json::Value* settings) { + //! [CharReaderBuilderDefaults] + (*settings)["collectComments"] = true; + (*settings)["allowComments"] = true; + (*settings)["strictRoot"] = false; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = false; + (*settings)["rejectDupKeys"] = false; + (*settings)["allowSpecialFloats"] = false; + //! [CharReaderBuilderDefaults] +} + +////////////////////////////////// +// global functions + +bool parseFromStream(CharReader::Factory const& fact, + JSONCPP_ISTREAM& sin, + Value* root, + JSONCPP_STRING* errs) { + JSONCPP_OSTRINGSTREAM ssin; + ssin << sin.rdbuf(); + JSONCPP_STRING doc = ssin.str(); + char const* begin = doc.data(); + char const* end = begin + doc.size(); + // Note that we do not actually need a null-terminator. + CharReaderPtr const reader(fact.newCharReader()); + return reader->parse(begin, end, root, errs); +} + +JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) { + CharReaderBuilder b; + JSONCPP_STRING errs; + bool ok = parseFromStream(b, sin, &root, &errs); + if (!ok) { + throwRuntimeError(errs); + } + return sin; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_valueiterator.inl +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +// included by json_value.cpp + +namespace Json { + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIteratorBase +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIteratorBase::ValueIteratorBase() + : current_(), isNull_(true) { +} + +ValueIteratorBase::ValueIteratorBase( + const Value::ObjectValues::iterator& current) + : current_(current), isNull_(false) {} + +Value& ValueIteratorBase::deref() const { + return current_->second; +} + +void ValueIteratorBase::increment() { + ++current_; +} + +void ValueIteratorBase::decrement() { + --current_; +} + +ValueIteratorBase::difference_type +ValueIteratorBase::computeDistance(const SelfType& other) const { +#ifdef JSON_USE_CPPTL_SMALLMAP + return other.current_ - current_; +#else + // Iterator for null value are initialized using the default + // constructor, which initialize current_ to the default + // std::map::iterator. As begin() and end() are two instance + // of the default std::map::iterator, they can not be compared. + // To allow this, we handle this comparison specifically. + if (isNull_ && other.isNull_) { + return 0; + } + + // Usage of std::distance is not portable (does not compile with Sun Studio 12 + // RogueWave STL, + // which is the one used by default). + // Using a portable hand-made version for non random iterator instead: + // return difference_type( std::distance( current_, other.current_ ) ); + difference_type myDistance = 0; + for (Value::ObjectValues::iterator it = current_; it != other.current_; + ++it) { + ++myDistance; + } + return myDistance; +#endif +} + +bool ValueIteratorBase::isEqual(const SelfType& other) const { + if (isNull_) { + return other.isNull_; + } + return current_ == other.current_; +} + +void ValueIteratorBase::copy(const SelfType& other) { + current_ = other.current_; + isNull_ = other.isNull_; +} + +Value ValueIteratorBase::key() const { + const Value::CZString czstring = (*current_).first; + if (czstring.data()) { + if (czstring.isStaticString()) + return Value(StaticString(czstring.data())); + return Value(czstring.data(), czstring.data() + czstring.length()); + } + return Value(czstring.index()); +} + +UInt ValueIteratorBase::index() const { + const Value::CZString czstring = (*current_).first; + if (!czstring.data()) + return czstring.index(); + return Value::UInt(-1); +} + +JSONCPP_STRING ValueIteratorBase::name() const { + char const* keey; + char const* end; + keey = memberName(&end); + if (!keey) return JSONCPP_STRING(); + return JSONCPP_STRING(keey, end); +} + +char const* ValueIteratorBase::memberName() const { + const char* cname = (*current_).first.data(); + return cname ? cname : ""; +} + +char const* ValueIteratorBase::memberName(char const** end) const { + const char* cname = (*current_).first.data(); + if (!cname) { + *end = NULL; + return NULL; + } + *end = cname + (*current_).first.length(); + return cname; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueConstIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueConstIterator::ValueConstIterator() {} + +ValueConstIterator::ValueConstIterator( + const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueConstIterator::ValueConstIterator(ValueIterator const& other) + : ValueIteratorBase(other) {} + +ValueConstIterator& ValueConstIterator:: +operator=(const ValueIteratorBase& other) { + copy(other); + return *this; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIterator::ValueIterator() {} + +ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueIterator::ValueIterator(const ValueConstIterator& other) + : ValueIteratorBase(other) { + throwRuntimeError("ConstIterator to Iterator should never be allowed."); +} + +ValueIterator::ValueIterator(const ValueIterator& other) + : ValueIteratorBase(other) {} + +ValueIterator& ValueIterator::operator=(const SelfType& other) { + copy(other); + return *this; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_valueiterator.inl +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_value.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#ifdef JSON_USE_CPPTL +#include +#endif +#include // min() +#include // size_t + +// Disable warning C4702 : unreachable code +#if defined(_MSC_VER) && _MSC_VER >= 1800 // VC++ 12.0 and above +#pragma warning(disable : 4702) +#endif + +#define JSON_ASSERT_UNREACHABLE assert(false) + +namespace Json { + +// This is a walkaround to avoid the static initialization of Value::null. +// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of +// 8 (instead of 4) as a bit of future-proofing. +#if defined(__ARMEL__) +#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) +#else +#define ALIGNAS(byte_alignment) +#endif +// static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; +// const unsigned char& kNullRef = kNull[0]; +// const Value& Value::null = reinterpret_cast(kNullRef); +// const Value& Value::nullRef = null; + +// static +Value const& Value::nullSingleton() { + static Value const nullStatic; + return nullStatic; +} + +// for backwards compatibility, we'll leave these global references around, but +// DO NOT use them in JSONCPP library code any more! +Value const& Value::null = Value::nullSingleton(); +Value const& Value::nullRef = Value::nullSingleton(); + +const Int Value::minInt = Int(~(UInt(-1) / 2)); +const Int Value::maxInt = Int(UInt(-1) / 2); +const UInt Value::maxUInt = UInt(-1); +#if defined(JSON_HAS_INT64) +const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); +const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); +const UInt64 Value::maxUInt64 = UInt64(-1); +// The constant is hard-coded because some compiler have trouble +// converting Value::maxUInt64 to a double correctly (AIX/xlC). +// Assumes that UInt64 is a 64 bits integer. +static const double maxUInt64AsDouble = 18446744073709551615.0; +#endif // defined(JSON_HAS_INT64) +const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); +const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); +const LargestUInt Value::maxLargestUInt = LargestUInt(-1); + +const UInt Value::defaultRealPrecision = 17; + +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +template +static inline bool InRange(double d, T min, U max) { + // The casts can lose precision, but we are looking only for + // an approximate range. Might fail on edge cases though. ~cdunn + // return d >= static_cast(min) && d <= static_cast(max); + return d >= min && d <= max; +} +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +static inline double integerToDouble(Json::UInt64 value) { + return static_cast(Int64(value / 2)) * 2.0 + + static_cast(Int64(value & 1)); +} + +template static inline double integerToDouble(T value) { + return static_cast(value); +} + +template +static inline bool InRange(double d, T min, U max) { + return d >= integerToDouble(min) && d <= integerToDouble(max); +} +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + +/** Duplicates the specified string value. + * @param value Pointer to the string to duplicate. Must be zero-terminated if + * length is "unknown". + * @param length Length of the value. if equals to unknown, then it will be + * computed using strlen(value). + * @return Pointer on the duplicate instance of string. + */ +static inline char* duplicateStringValue(const char* value, size_t length) { + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + if (length >= static_cast(Value::maxInt)) + length = Value::maxInt - 1; + + char* newString = static_cast(malloc(length + 1)); + if (newString == NULL) { + throwRuntimeError("in Json::Value::duplicateStringValue(): " + "Failed to allocate string value buffer"); + } + memcpy(newString, value, length); + newString[length] = 0; + return newString; +} + +/* Record the length as a prefix. + */ +static inline char* duplicateAndPrefixStringValue(const char* value, + unsigned int length) { + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + JSON_ASSERT_MESSAGE(length <= static_cast(Value::maxInt) - + sizeof(unsigned) - 1U, + "in Json::Value::duplicateAndPrefixStringValue(): " + "length too big for prefixing"); + unsigned actualLength = length + static_cast(sizeof(unsigned)) + 1U; + char* newString = static_cast(malloc(actualLength)); + if (newString == 0) { + throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): " + "Failed to allocate string value buffer"); + } + *reinterpret_cast(newString) = length; + memcpy(newString + sizeof(unsigned), value, length); + newString[actualLength - 1U] = + 0; // to avoid buffer over-run accidents by users later + return newString; +} +inline static void decodePrefixedString(bool isPrefixed, + char const* prefixed, + unsigned* length, + char const** value) { + if (!isPrefixed) { + *length = static_cast(strlen(prefixed)); + *value = prefixed; + } else { + *length = *reinterpret_cast(prefixed); + *value = prefixed + sizeof(unsigned); + } +} +/** Free the string duplicated by + * duplicateStringValue()/duplicateAndPrefixStringValue(). + */ +#if JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { + unsigned length = 0; + char const* valueDecoded; + decodePrefixedString(true, value, &length, &valueDecoded); + size_t const size = sizeof(unsigned) + length + 1U; + memset(value, 0, size); + free(value); +} +static inline void releaseStringValue(char* value, unsigned length) { + // length==0 => we allocated the strings memory + size_t size = (length == 0) ? strlen(value) : length; + memset(value, 0, size); + free(value); +} +#else // !JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { free(value); } +static inline void releaseStringValue(char* value, unsigned) { free(value); } +#endif // JSONCPP_USING_SECURE_MEMORY + +} // namespace Json + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#if !defined(JSON_IS_AMALGAMATION) + +#include "json_valueiterator.inl" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +Exception::Exception(JSONCPP_STRING const& msg) : msg_(msg) {} +Exception::~Exception() JSONCPP_NOEXCEPT {} +char const* Exception::what() const JSONCPP_NOEXCEPT { return msg_.c_str(); } +RuntimeError::RuntimeError(JSONCPP_STRING const& msg) : Exception(msg) {} +LogicError::LogicError(JSONCPP_STRING const& msg) : Exception(msg) {} +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) { + throw RuntimeError(msg); +} +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) { + throw LogicError(msg); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CommentInfo +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +Value::CommentInfo::CommentInfo() : comment_(0) {} + +Value::CommentInfo::~CommentInfo() { + if (comment_) + releaseStringValue(comment_, 0u); +} + +void Value::CommentInfo::setComment(const char* text, size_t len) { + if (comment_) { + releaseStringValue(comment_, 0u); + comment_ = 0; + } + JSON_ASSERT(text != 0); + JSON_ASSERT_MESSAGE( + text[0] == '\0' || text[0] == '/', + "in Json::Value::setComment(): Comments must start with /"); + // It seems that /**/ style comments are acceptable as well. + comment_ = duplicateStringValue(text, len); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CZString +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +// Notes: policy_ indicates if the string was allocated when +// a string is stored. + +Value::CZString::CZString(ArrayIndex index) : cstr_(0), index_(index) {} + +Value::CZString::CZString(char const* str, + unsigned length, + DuplicationPolicy allocate) + : cstr_(str) { + // allocate != duplicate + storage_.policy_ = allocate & 0x3; + storage_.length_ = length & 0x3FFFFFFF; +} + +Value::CZString::CZString(const CZString& other) { + cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 0 + ? duplicateStringValue(other.cstr_, other.storage_.length_) + : other.cstr_); + storage_.policy_ = + static_cast( + other.cstr_ + ? (static_cast(other.storage_.policy_) == + noDuplication + ? noDuplication + : duplicate) + : static_cast(other.storage_.policy_)) & + 3U; + storage_.length_ = other.storage_.length_; +} + +#if JSON_HAS_RVALUE_REFERENCES +Value::CZString::CZString(CZString&& other) + : cstr_(other.cstr_), index_(other.index_) { + other.cstr_ = nullptr; +} +#endif + +Value::CZString::~CZString() { + if (cstr_ && storage_.policy_ == duplicate) { + releaseStringValue(const_cast(cstr_), + storage_.length_ + 1u); // +1 for null terminating + // character for sake of + // completeness but not actually + // necessary + } +} + +void Value::CZString::swap(CZString& other) { + std::swap(cstr_, other.cstr_); + std::swap(index_, other.index_); +} + +Value::CZString& Value::CZString::operator=(const CZString& other) { + cstr_ = other.cstr_; + index_ = other.index_; + return *this; +} + +#if JSON_HAS_RVALUE_REFERENCES +Value::CZString& Value::CZString::operator=(CZString&& other) { + cstr_ = other.cstr_; + index_ = other.index_; + other.cstr_ = nullptr; + return *this; +} +#endif + +bool Value::CZString::operator<(const CZString& other) const { + if (!cstr_) + return index_ < other.index_; + // return strcmp(cstr_, other.cstr_) < 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + unsigned min_len = std::min(this_len, other_len); + JSON_ASSERT(this->cstr_ && other.cstr_); + int comp = memcmp(this->cstr_, other.cstr_, min_len); + if (comp < 0) + return true; + if (comp > 0) + return false; + return (this_len < other_len); +} + +bool Value::CZString::operator==(const CZString& other) const { + if (!cstr_) + return index_ == other.index_; + // return strcmp(cstr_, other.cstr_) == 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + if (this_len != other_len) + return false; + JSON_ASSERT(this->cstr_ && other.cstr_); + int comp = memcmp(this->cstr_, other.cstr_, this_len); + return comp == 0; +} + +ArrayIndex Value::CZString::index() const { return index_; } + +// const char* Value::CZString::c_str() const { return cstr_; } +const char* Value::CZString::data() const { return cstr_; } +unsigned Value::CZString::length() const { return storage_.length_; } +bool Value::CZString::isStaticString() const { + return storage_.policy_ == noDuplication; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::Value +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +/*! \internal Default constructor initialization must be equivalent to: + * memset( this, 0, sizeof(Value) ) + * This optimization is used in ValueInternalMap fast allocator. + */ +Value::Value(ValueType type) { + static char const emptyString[] = ""; + initBasic(type); + switch (type) { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + // allocated_ == false, so this is safe. + value_.string_ = const_cast(static_cast(emptyString)); + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +Value::Value(Int value) { + initBasic(intValue); + value_.int_ = value; +} + +Value::Value(UInt value) { + initBasic(uintValue); + value_.uint_ = value; +} +#if defined(JSON_HAS_INT64) +Value::Value(Int64 value) { + initBasic(intValue); + value_.int_ = value; +} +Value::Value(UInt64 value) { + initBasic(uintValue); + value_.uint_ = value; +} +#endif // defined(JSON_HAS_INT64) + +Value::Value(double value) { + initBasic(realValue); + value_.real_ = value; +} + +Value::Value(const char* value) { + initBasic(stringValue, true); + JSON_ASSERT_MESSAGE(value != NULL, "Null Value Passed to Value Constructor"); + value_.string_ = duplicateAndPrefixStringValue( + value, static_cast(strlen(value))); +} + +Value::Value(const char* begin, const char* end) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(begin, static_cast(end - begin)); +} + +Value::Value(const JSONCPP_STRING& value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue( + value.data(), static_cast(value.length())); +} + +Value::Value(const StaticString& value) { + initBasic(stringValue); + value_.string_ = const_cast(value.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value::Value(const CppTL::ConstString& value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue( + value, static_cast(value.length())); +} +#endif + +Value::Value(bool value) { + initBasic(booleanValue); + value_.bool_ = value; +} + +Value::Value(const Value& other) { + dupPayload(other); + dupMeta(other); +} + +#if JSON_HAS_RVALUE_REFERENCES +// Move constructor +Value::Value(Value&& other) { + initBasic(nullValue); + swap(other); +} +#endif + +Value::~Value() { + releasePayload(); + + delete[] comments_; + + value_.uint_ = 0; +} + +Value& Value::operator=(Value other) { + swap(other); + return *this; +} + +void Value::swapPayload(Value& other) { + ValueType temp = type_; + type_ = other.type_; + other.type_ = temp; + std::swap(value_, other.value_); + int temp2 = allocated_; + allocated_ = other.allocated_; + other.allocated_ = temp2 & 0x1; +} + +void Value::copyPayload(const Value& other) { + releasePayload(); + dupPayload(other); +} + +void Value::swap(Value& other) { + swapPayload(other); + std::swap(comments_, other.comments_); + std::swap(start_, other.start_); + std::swap(limit_, other.limit_); +} + +void Value::copy(const Value& other) { + copyPayload(other); + delete[] comments_; + dupMeta(other); +} + +ValueType Value::type() const { return type_; } + +int Value::compare(const Value& other) const { + if (*this < other) + return -1; + if (*this > other) + return 1; + return 0; +} + +bool Value::operator<(const Value& other) const { + int typeDelta = type_ - other.type_; + if (typeDelta) + return typeDelta < 0 ? true : false; + switch (type_) { + case nullValue: + return false; + case intValue: + return value_.int_ < other.value_.int_; + case uintValue: + return value_.uint_ < other.value_.uint_; + case realValue: + return value_.real_ < other.value_.real_; + case booleanValue: + return value_.bool_ < other.value_.bool_; + case stringValue: { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + if (other.value_.string_) + return true; + else + return false; + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, + &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, + &other_str); + unsigned min_len = std::min(this_len, other_len); + JSON_ASSERT(this_str && other_str); + int comp = memcmp(this_str, other_str, min_len); + if (comp < 0) + return true; + if (comp > 0) + return false; + return (this_len < other_len); + } + case arrayValue: + case objectValue: { + int delta = int(value_.map_->size() - other.value_.map_->size()); + if (delta) + return delta < 0; + return (*value_.map_) < (*other.value_.map_); + } + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator<=(const Value& other) const { return !(other < *this); } + +bool Value::operator>=(const Value& other) const { return !(*this < other); } + +bool Value::operator>(const Value& other) const { return other < *this; } + +bool Value::operator==(const Value& other) const { + // if ( type_ != other.type_ ) + // GCC 2.95.3 says: + // attempt to take address of bit-field structure member `Json::Value::type_' + // Beats me, but a temp solves the problem. + int temp = other.type_; + if (type_ != temp) + return false; + switch (type_) { + case nullValue: + return true; + case intValue: + return value_.int_ == other.value_.int_; + case uintValue: + return value_.uint_ == other.value_.uint_; + case realValue: + return value_.real_ == other.value_.real_; + case booleanValue: + return value_.bool_ == other.value_.bool_; + case stringValue: { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + return (value_.string_ == other.value_.string_); + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, + &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, + &other_str); + if (this_len != other_len) + return false; + JSON_ASSERT(this_str && other_str); + int comp = memcmp(this_str, other_str, this_len); + return comp == 0; + } + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() && + (*value_.map_) == (*other.value_.map_); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator!=(const Value& other) const { return !(*this == other); } + +const char* Value::asCString() const { + JSON_ASSERT_MESSAGE(type_ == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) + return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, + &this_str); + return this_str; +} + +#if JSONCPP_USING_SECURE_MEMORY +unsigned Value::getCStringLength() const { + JSON_ASSERT_MESSAGE(type_ == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) + return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, + &this_str); + return this_len; +} +#endif + +bool Value::getString(char const** begin, char const** end) const { + if (type_ != stringValue) + return false; + if (value_.string_ == 0) + return false; + unsigned length; + decodePrefixedString(this->allocated_, this->value_.string_, &length, begin); + *end = *begin + length; + return true; +} + +JSONCPP_STRING Value::asString() const { + switch (type_) { + case nullValue: + return ""; + case stringValue: { + if (value_.string_ == 0) + return ""; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, + &this_str); + return JSONCPP_STRING(this_str, this_len); + } + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + return valueToString(value_.int_); + case uintValue: + return valueToString(value_.uint_); + case realValue: + return valueToString(value_.real_); + default: + JSON_FAIL_MESSAGE("Type is not convertible to string"); + } +} + +#ifdef JSON_USE_CPPTL +CppTL::ConstString Value::asConstString() const { + unsigned len; + char const* str; + decodePrefixedString(allocated_, value_.string_, &len, &str); + return CppTL::ConstString(str, len); +} +#endif + +Value::Int Value::asInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); + return Int(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); + return Int(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), + "double out of Int range"); + return Int(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int."); +} + +Value::UInt Value::asUInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); + return UInt(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); + return UInt(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), + "double out of UInt range"); + return UInt(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt."); +} + +#if defined(JSON_HAS_INT64) + +Value::Int64 Value::asInt64() const { + switch (type_) { + case intValue: + return Int64(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); + return Int64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), + "double out of Int64 range"); + return Int64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int64."); +} + +Value::UInt64 Value::asUInt64() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); + return UInt64(value_.int_); + case uintValue: + return UInt64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), + "double out of UInt64 range"); + return UInt64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); +} +#endif // if defined(JSON_HAS_INT64) + +LargestInt Value::asLargestInt() const { +#if defined(JSON_NO_INT64) + return asInt(); +#else + return asInt64(); +#endif +} + +LargestUInt Value::asLargestUInt() const { +#if defined(JSON_NO_INT64) + return asUInt(); +#else + return asUInt64(); +#endif +} + +double Value::asDouble() const { + switch (type_) { + case intValue: + return static_cast(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return integerToDouble(value_.uint_); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return value_.real_; + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to double."); +} + +float Value::asFloat() const { + switch (type_) { + case intValue: + return static_cast(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + // This can fail (silently?) if the value is bigger than MAX_FLOAT. + return static_cast(integerToDouble(value_.uint_)); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return static_cast(value_.real_); + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0f : 0.0f; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to float."); +} + +bool Value::asBool() const { + switch (type_) { + case booleanValue: + return value_.bool_; + case nullValue: + return false; + case intValue: + return value_.int_ ? true : false; + case uintValue: + return value_.uint_ ? true : false; + case realValue: + // This is kind of strange. Not recommended. + return (value_.real_ != 0.0) ? true : false; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to bool."); +} + +bool Value::isConvertibleTo(ValueType other) const { + switch (other) { + case nullValue: + return (isNumeric() && asDouble() == 0.0) || + (type_ == booleanValue && value_.bool_ == false) || + (type_ == stringValue && asString().empty()) || + (type_ == arrayValue && value_.map_->size() == 0) || + (type_ == objectValue && value_.map_->size() == 0) || + type_ == nullValue; + case intValue: + return isInt() || + (type_ == realValue && InRange(value_.real_, minInt, maxInt)) || + type_ == booleanValue || type_ == nullValue; + case uintValue: + return isUInt() || + (type_ == realValue && InRange(value_.real_, 0, maxUInt)) || + type_ == booleanValue || type_ == nullValue; + case realValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case booleanValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case stringValue: + return isNumeric() || type_ == booleanValue || type_ == stringValue || + type_ == nullValue; + case arrayValue: + return type_ == arrayValue || type_ == nullValue; + case objectValue: + return type_ == objectValue || type_ == nullValue; + } + JSON_ASSERT_UNREACHABLE; + return false; +} + +/// Number of values in array or object +ArrayIndex Value::size() const { + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + case stringValue: + return 0; + case arrayValue: // size of the array is highest index + 1 + if (!value_.map_->empty()) { + ObjectValues::const_iterator itLast = value_.map_->end(); + --itLast; + return (*itLast).first.index() + 1; + } + return 0; + case objectValue: + return ArrayIndex(value_.map_->size()); + } + JSON_ASSERT_UNREACHABLE; + return 0; // unreachable; +} + +bool Value::empty() const { + if (isNull() || isArray() || isObject()) + return size() == 0u; + else + return false; +} + +Value::operator bool() const { return !isNull(); } + +void Value::clear() { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || + type_ == objectValue, + "in Json::Value::clear(): requires complex value"); + start_ = 0; + limit_ = 0; + switch (type_) { + case arrayValue: + case objectValue: + value_.map_->clear(); + break; + default: + break; + } +} + +void Value::resize(ArrayIndex newSize) { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue, + "in Json::Value::resize(): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + ArrayIndex oldSize = size(); + if (newSize == 0) + clear(); + else if (newSize > oldSize) + this->operator[](newSize - 1); + else { + for (ArrayIndex index = newSize; index < oldSize; ++index) { + value_.map_->erase(index); + } + JSON_ASSERT(size() == newSize); + } +} + +Value& Value::operator[](ArrayIndex index) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + CZString key(index); + ObjectValues::iterator it = value_.map_->lower_bound(key); + if (it != value_.map_->end() && (*it).first == key) + return (*it).second; + + ObjectValues::value_type defaultValue(key, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + return (*it).second; +} + +Value& Value::operator[](int index) { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index): index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +const Value& Value::operator[](ArrayIndex index) const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); + if (type_ == nullValue) + return nullSingleton(); + CZString key(index); + ObjectValues::const_iterator it = value_.map_->find(key); + if (it == value_.map_->end()) + return nullSingleton(); + return (*it).second; +} + +const Value& Value::operator[](int index) const { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index) const: index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +void Value::initBasic(ValueType type, bool allocated) { + type_ = type; + allocated_ = allocated; + comments_ = 0; + start_ = 0; + limit_ = 0; +} + +void Value::dupPayload(const Value& other) { + type_ = other.type_; + allocated_ = false; + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if (other.value_.string_ && other.allocated_) { + unsigned len; + char const* str; + decodePrefixedString(other.allocated_, other.value_.string_, &len, &str); + value_.string_ = duplicateAndPrefixStringValue(str, len); + allocated_ = true; + } else { + value_.string_ = other.value_.string_; + } + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(*other.value_.map_); + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +void Value::releasePayload() { + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if (allocated_) + releasePrefixedStringValue(value_.string_); + break; + case arrayValue: + case objectValue: + delete value_.map_; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +void Value::dupMeta(const Value& other) { + if (other.comments_) { + comments_ = new CommentInfo[numberOfCommentPlacement]; + for (int comment = 0; comment < numberOfCommentPlacement; ++comment) { + const CommentInfo& otherComment = other.comments_[comment]; + if (otherComment.comment_) + comments_[comment].setComment(otherComment.comment_, + strlen(otherComment.comment_)); + } + } else { + comments_ = 0; + } + start_ = other.start_; + limit_ = other.limit_; +} + +// Access an object value by name, create a null member if it does not exist. +// @pre Type of '*this' is object or null. +// @param key is null-terminated. +Value& Value::resolveReference(const char* key) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey(key, static_cast(strlen(key)), + CZString::noDuplication); // NOTE! + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +// @param key is not null-terminated. +Value& Value::resolveReference(char const* key, char const* end) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(key, end): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey(key, static_cast(end - key), + CZString::duplicateOnCopy); + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +Value Value::get(ArrayIndex index, const Value& defaultValue) const { + const Value* value = &((*this)[index]); + return value == &nullSingleton() ? defaultValue : *value; +} + +bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } + +Value const* Value::find(char const* begin, char const* end) const { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, + "in Json::Value::find(key, end, found): requires " + "objectValue or nullValue"); + if (type_ == nullValue) + return NULL; + CZString actualKey(begin, static_cast(end - begin), + CZString::noDuplication); + ObjectValues::const_iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return NULL; + return &(*it).second; +} +const Value& Value::operator[](const char* key) const { + Value const* found = find(key, key + strlen(key)); + if (!found) + return nullSingleton(); + return *found; +} +Value const& Value::operator[](JSONCPP_STRING const& key) const { + Value const* found = find(key.data(), key.data() + key.length()); + if (!found) + return nullSingleton(); + return *found; +} + +Value& Value::operator[](const char* key) { + return resolveReference(key, key + strlen(key)); +} + +Value& Value::operator[](const JSONCPP_STRING& key) { + return resolveReference(key.data(), key.data() + key.length()); +} + +Value& Value::operator[](const StaticString& key) { + return resolveReference(key.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value& Value::operator[](const CppTL::ConstString& key) { + return resolveReference(key.c_str(), key.end_c_str()); +} +Value const& Value::operator[](CppTL::ConstString const& key) const { + Value const* found = find(key.c_str(), key.end_c_str()); + if (!found) + return nullSingleton(); + return *found; +} +#endif + +Value& Value::append(const Value& value) { return (*this)[size()] = value; } + +#if JSON_HAS_RVALUE_REFERENCES +Value& Value::append(Value&& value) { + return (*this)[size()] = std::move(value); +} +#endif + +Value Value::get(char const* begin, + char const* end, + Value const& defaultValue) const { + Value const* found = find(begin, end); + return !found ? defaultValue : *found; +} +Value Value::get(char const* key, Value const& defaultValue) const { + return get(key, key + strlen(key), defaultValue); +} +Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue) const { + return get(key.data(), key.data() + key.length(), defaultValue); +} + +bool Value::removeMember(const char* begin, const char* end, Value* removed) { + if (type_ != objectValue) { + return false; + } + CZString actualKey(begin, static_cast(end - begin), + CZString::noDuplication); + ObjectValues::iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return false; + if (removed) +#if JSON_HAS_RVALUE_REFERENCES + *removed = std::move(it->second); +#else + *removed = it->second; +#endif + value_.map_->erase(it); + return true; +} +bool Value::removeMember(const char* key, Value* removed) { + return removeMember(key, key + strlen(key), removed); +} +bool Value::removeMember(JSONCPP_STRING const& key, Value* removed) { + return removeMember(key.data(), key.data() + key.length(), removed); +} +void Value::removeMember(const char* key) { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, + "in Json::Value::removeMember(): requires objectValue"); + if (type_ == nullValue) + return; + + CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication); + value_.map_->erase(actualKey); +} +void Value::removeMember(const JSONCPP_STRING& key) { + removeMember(key.c_str()); +} + +bool Value::removeIndex(ArrayIndex index, Value* removed) { + if (type_ != arrayValue) { + return false; + } + CZString key(index); + ObjectValues::iterator it = value_.map_->find(key); + if (it == value_.map_->end()) { + return false; + } + if (removed) + *removed = it->second; + ArrayIndex oldSize = size(); + // shift left all items left, into the place of the "removed" + for (ArrayIndex i = index; i < (oldSize - 1); ++i) { + CZString keey(i); + (*value_.map_)[keey] = (*this)[i + 1]; + } + // erase the last one ("leftover") + CZString keyLast(oldSize - 1); + ObjectValues::iterator itLast = value_.map_->find(keyLast); + value_.map_->erase(itLast); + return true; +} + +#ifdef JSON_USE_CPPTL +Value Value::get(const CppTL::ConstString& key, + const Value& defaultValue) const { + return get(key.c_str(), key.end_c_str(), defaultValue); +} +#endif + +bool Value::isMember(char const* begin, char const* end) const { + Value const* value = find(begin, end); + return NULL != value; +} +bool Value::isMember(char const* key) const { + return isMember(key, key + strlen(key)); +} +bool Value::isMember(JSONCPP_STRING const& key) const { + return isMember(key.data(), key.data() + key.length()); +} + +#ifdef JSON_USE_CPPTL +bool Value::isMember(const CppTL::ConstString& key) const { + return isMember(key.c_str(), key.end_c_str()); +} +#endif + +Value::Members Value::getMemberNames() const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::getMemberNames(), value must be objectValue"); + if (type_ == nullValue) + return Value::Members(); + Members members; + members.reserve(value_.map_->size()); + ObjectValues::const_iterator it = value_.map_->begin(); + ObjectValues::const_iterator itEnd = value_.map_->end(); + for (; it != itEnd; ++it) { + members.push_back(JSONCPP_STRING((*it).first.data(), (*it).first.length())); + } + return members; +} +// +//# ifdef JSON_USE_CPPTL +// EnumMemberNames +// Value::enumMemberNames() const +//{ +// if ( type_ == objectValue ) +// { +// return CppTL::Enum::any( CppTL::Enum::transform( +// CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), +// MemberNamesTransform() ) ); +// } +// return EnumMemberNames(); +//} +// +// +// EnumValues +// Value::enumValues() const +//{ +// if ( type_ == objectValue || type_ == arrayValue ) +// return CppTL::Enum::anyValues( *(value_.map_), +// CppTL::Type() ); +// return EnumValues(); +//} +// +//# endif + +static bool IsIntegral(double d) { + double integral_part; + return modf(d, &integral_part) == 0.0; +} + +bool Value::isNull() const { return type_ == nullValue; } + +bool Value::isBool() const { return type_ == booleanValue; } + +bool Value::isInt() const { + switch (type_) { + case intValue: +#if defined(JSON_HAS_INT64) + return value_.int_ >= minInt && value_.int_ <= maxInt; +#else + return true; +#endif + case uintValue: + return value_.uint_ <= UInt(maxInt); + case realValue: + return value_.real_ >= minInt && value_.real_ <= maxInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isUInt() const { + switch (type_) { + case intValue: +#if defined(JSON_HAS_INT64) + return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); +#else + return value_.int_ >= 0; +#endif + case uintValue: +#if defined(JSON_HAS_INT64) + return value_.uint_ <= maxUInt; +#else + return true; +#endif + case realValue: + return value_.real_ >= 0 && value_.real_ <= maxUInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return true; + case uintValue: + return value_.uint_ <= UInt64(maxInt64); + case realValue: + // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a + // double, so double(maxInt64) will be rounded up to 2^63. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < double(maxInt64) && IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isUInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return value_.int_ >= 0; + case uintValue: + return true; + case realValue: + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && + IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isIntegral() const { + switch (type_) { + case intValue: + case uintValue: + return true; + case realValue: +#if defined(JSON_HAS_INT64) + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_); +#else + return value_.real_ >= minInt && value_.real_ <= maxUInt && + IsIntegral(value_.real_); +#endif // JSON_HAS_INT64 + default: + break; + } + return false; +} + +bool Value::isDouble() const { + return type_ == intValue || type_ == uintValue || type_ == realValue; +} + +bool Value::isNumeric() const { return isDouble(); } + +bool Value::isString() const { return type_ == stringValue; } + +bool Value::isArray() const { return type_ == arrayValue; } + +bool Value::isObject() const { return type_ == objectValue; } + +void Value::setComment(const char* comment, + size_t len, + CommentPlacement placement) { + if (!comments_) + comments_ = new CommentInfo[numberOfCommentPlacement]; + if ((len > 0) && (comment[len - 1] == '\n')) { + // Always discard trailing newline, to aid indentation. + len -= 1; + } + comments_[placement].setComment(comment, len); +} + +void Value::setComment(const char* comment, CommentPlacement placement) { + setComment(comment, strlen(comment), placement); +} + +void Value::setComment(const JSONCPP_STRING& comment, + CommentPlacement placement) { + setComment(comment.c_str(), comment.length(), placement); +} + +bool Value::hasComment(CommentPlacement placement) const { + return comments_ != 0 && comments_[placement].comment_ != 0; +} + +JSONCPP_STRING Value::getComment(CommentPlacement placement) const { + if (hasComment(placement)) + return comments_[placement].comment_; + return ""; +} + +void Value::setOffsetStart(ptrdiff_t start) { start_ = start; } + +void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; } + +ptrdiff_t Value::getOffsetStart() const { return start_; } + +ptrdiff_t Value::getOffsetLimit() const { return limit_; } + +JSONCPP_STRING Value::toStyledString() const { + StreamWriterBuilder builder; + + JSONCPP_STRING out = this->hasComment(commentBefore) ? "\n" : ""; + out += Json::writeString(builder, *this); + out += '\n'; + + return out; +} + +Value::const_iterator Value::begin() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->begin()); + break; + default: + break; + } + return const_iterator(); +} + +Value::const_iterator Value::end() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->end()); + break; + default: + break; + } + return const_iterator(); +} + +Value::iterator Value::begin() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->begin()); + break; + default: + break; + } + return iterator(); +} + +Value::iterator Value::end() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->end()); + break; + default: + break; + } + return iterator(); +} + +// class PathArgument +// ////////////////////////////////////////////////////////////////// + +PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} + +PathArgument::PathArgument(ArrayIndex index) + : key_(), index_(index), kind_(kindIndex) {} + +PathArgument::PathArgument(const char* key) + : key_(key), index_(), kind_(kindKey) {} + +PathArgument::PathArgument(const JSONCPP_STRING& key) + : key_(key.c_str()), index_(), kind_(kindKey) {} + +// class Path +// ////////////////////////////////////////////////////////////////// + +Path::Path(const JSONCPP_STRING& path, + const PathArgument& a1, + const PathArgument& a2, + const PathArgument& a3, + const PathArgument& a4, + const PathArgument& a5) { + InArgs in; + in.reserve(5); + in.push_back(&a1); + in.push_back(&a2); + in.push_back(&a3); + in.push_back(&a4); + in.push_back(&a5); + makePath(path, in); +} + +void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) { + const char* current = path.c_str(); + const char* end = current + path.length(); + InArgs::const_iterator itInArg = in.begin(); + while (current != end) { + if (*current == '[') { + ++current; + if (*current == '%') + addPathInArg(path, in, itInArg, PathArgument::kindIndex); + else { + ArrayIndex index = 0; + for (; current != end && *current >= '0' && *current <= '9'; ++current) + index = index * 10 + ArrayIndex(*current - '0'); + args_.push_back(index); + } + if (current == end || *++current != ']') + invalidPath(path, int(current - path.c_str())); + } else if (*current == '%') { + addPathInArg(path, in, itInArg, PathArgument::kindKey); + ++current; + } else if (*current == '.' || *current == ']') { + ++current; + } else { + const char* beginName = current; + while (current != end && !strchr("[.", *current)) + ++current; + args_.push_back(JSONCPP_STRING(beginName, current)); + } + } +} + +void Path::addPathInArg(const JSONCPP_STRING& /*path*/, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind) { + if (itInArg == in.end()) { + // Error: missing argument %d + } else if ((*itInArg)->kind_ != kind) { + // Error: bad argument type + } else { + args_.push_back(**itInArg++); + } +} + +void Path::invalidPath(const JSONCPP_STRING& /*path*/, int /*location*/) { + // Error: invalid path. +} + +const Value& Path::resolve(const Value& root) const { + const Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray() || !node->isValidIndex(arg.index_)) { + // Error: unable to resolve path (array value expected at position... + return Value::null; + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: unable to resolve path (object value expected at position...) + return Value::null; + } + node = &((*node)[arg.key_]); + if (node == &Value::nullSingleton()) { + // Error: unable to resolve path (object has no member named '' at + // position...) + return Value::null; + } + } + } + return *node; +} + +Value Path::resolve(const Value& root, const Value& defaultValue) const { + const Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray() || !node->isValidIndex(arg.index_)) + return defaultValue; + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) + return defaultValue; + node = &((*node)[arg.key_]); + if (node == &Value::nullSingleton()) + return defaultValue; + } + } + return *node; +} + +Value& Path::make(Value& root) const { + Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray()) { + // Error: node is not an array at position ... + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: node is not an object at position... + } + node = &((*node)[arg.key_]); + } + } + return *node; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_value.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include "json_tool.h" +#include +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include +#include + +#if __cplusplus >= 201103L +#include +#include + +#if !defined(isnan) +#define isnan std::isnan +#endif + +#if !defined(isfinite) +#define isfinite std::isfinite +#endif + +#if !defined(snprintf) +#define snprintf std::snprintf +#endif +#else +#include +#include + +#if defined(_MSC_VER) +#if !defined(isnan) +#include +#define isnan _isnan +#endif + +#if !defined(isfinite) +#include +#define isfinite _finite +#endif + +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 +#if !defined(snprintf) +#define snprintf _snprintf +#endif +#endif + +#if defined(__sun) && defined(__SVR4) // Solaris +#if !defined(isfinite) +#include +#define isfinite finite +#endif +#endif + +#if defined(__hpux) +#if !defined(isfinite) +#if defined(__ia64) && !defined(finite) +#define isfinite(x) \ + ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x))) +#endif +#endif +#endif + +#if !defined(isnan) +// IEEE standard states that NaN values will not compare to themselves +#define isnan(x) (x != x) +#endif + +#if !defined(isfinite) +#define isfinite finite +#endif +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr StreamWriterPtr; +#else +typedef std::auto_ptr StreamWriterPtr; +#endif + +JSONCPP_STRING valueToString(LargestInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + if (value == Value::minLargestInt) { + uintToString(LargestUInt(Value::maxLargestInt) + 1, current); + *--current = '-'; + } else if (value < 0) { + uintToString(LargestUInt(-value), current); + *--current = '-'; + } else { + uintToString(LargestUInt(value), current); + } + assert(current >= buffer); + return current; +} + +JSONCPP_STRING valueToString(LargestUInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + uintToString(value, current); + assert(current >= buffer); + return current; +} + +#if defined(JSON_HAS_INT64) + +JSONCPP_STRING valueToString(Int value) { + return valueToString(LargestInt(value)); +} + +JSONCPP_STRING valueToString(UInt value) { + return valueToString(LargestUInt(value)); +} + +#endif // # if defined(JSON_HAS_INT64) + +namespace { +JSONCPP_STRING valueToString(double value, + bool useSpecialFloats, + unsigned int precision, + PrecisionType precisionType) { + // Print into the buffer. We need not request the alternative representation + // that always has a decimal point because JSON doesn't distinguish the + // concepts of reals and integers. + if (!isfinite(value)) { + static const char* const reps[2][3] = { { "NaN", "-Infinity", "Infinity" }, + { "null", "-1e+9999", "1e+9999" } }; + return reps[useSpecialFloats ? 0 : 1] + [isnan(value) ? 0 : (value < 0) ? 1 : 2]; + } + + JSONCPP_STRING buffer(size_t(36), '\0'); + while (true) { + int len = snprintf( + &*buffer.begin(), buffer.size(), + (precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f", + precision, value); + assert(len >= 0); + size_t wouldPrint = static_cast(len); + if (wouldPrint >= buffer.size()) { + buffer.resize(wouldPrint + 1); + continue; + } + buffer.resize(wouldPrint); + break; + } + + buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end()); + + // strip the zero padding from the right + if (precisionType == PrecisionType::decimalPlaces) { + buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end()); + } + + // try to ensure we preserve the fact that this was given to us as a double on + // input + if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) { + buffer += ".0"; + } + return buffer; +} +} // namespace + +JSONCPP_STRING valueToString(double value, + unsigned int precision, + PrecisionType precisionType) { + return valueToString(value, false, precision, precisionType); +} + +JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; } + +static bool isAnyCharRequiredQuoting(char const* s, size_t n) { + assert(s || !n); + + char const* const end = s + n; + for (char const* cur = s; cur < end; ++cur) { + if (*cur == '\\' || *cur == '\"' || *cur < ' ' || + static_cast(*cur) < 0x80) + return true; + } + return false; +} + +static unsigned int utf8ToCodepoint(const char*& s, const char* e) { + const unsigned int REPLACEMENT_CHARACTER = 0xFFFD; + + unsigned int firstByte = static_cast(*s); + + if (firstByte < 0x80) + return firstByte; + + if (firstByte < 0xE0) { + if (e - s < 2) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = + ((firstByte & 0x1F) << 6) | (static_cast(s[1]) & 0x3F); + s += 1; + // oversized encoded characters are invalid + return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated; + } + + if (firstByte < 0xF0) { + if (e - s < 3) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = ((firstByte & 0x0F) << 12) | + ((static_cast(s[1]) & 0x3F) << 6) | + (static_cast(s[2]) & 0x3F); + s += 2; + // surrogates aren't valid codepoints itself + // shouldn't be UTF-8 encoded + if (calculated >= 0xD800 && calculated <= 0xDFFF) + return REPLACEMENT_CHARACTER; + // oversized encoded characters are invalid + return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated; + } + + if (firstByte < 0xF8) { + if (e - s < 4) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = ((firstByte & 0x07) << 18) | + ((static_cast(s[1]) & 0x3F) << 12) | + ((static_cast(s[2]) & 0x3F) << 6) | + (static_cast(s[3]) & 0x3F); + s += 3; + // oversized encoded characters are invalid + return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated; + } + + return REPLACEMENT_CHARACTER; +} + +static const char hex2[] = "000102030405060708090a0b0c0d0e0f" + "101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f" + "505152535455565758595a5b5c5d5e5f" + "606162636465666768696a6b6c6d6e6f" + "707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; + +static JSONCPP_STRING toHex16Bit(unsigned int x) { + const unsigned int hi = (x >> 8) & 0xff; + const unsigned int lo = x & 0xff; + JSONCPP_STRING result(4, ' '); + result[0] = hex2[2 * hi]; + result[1] = hex2[2 * hi + 1]; + result[2] = hex2[2 * lo]; + result[3] = hex2[2 * lo + 1]; + return result; +} + +static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { + if (value == NULL) + return ""; + + if (!isAnyCharRequiredQuoting(value, length)) + return JSONCPP_STRING("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + JSONCPP_STRING::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL + JSONCPP_STRING result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + char const* end = value + length; + for (const char* c = value; c != end; ++c) { + switch (*c) { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + // case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something.) + // blep notes: actually escaping \/ may be useful in javascript to avoid = 0x20) + result += static_cast(cp); + else if (cp < 0x10000) { // codepoint is in Basic Multilingual Plane + result += "\\u"; + result += toHex16Bit(cp); + } else { // codepoint is not in Basic Multilingual Plane + // convert to surrogate pair first + cp -= 0x10000; + result += "\\u"; + result += toHex16Bit((cp >> 10) + 0xD800); + result += "\\u"; + result += toHex16Bit((cp & 0x3FF) + 0xDC00); + } + } break; + //default: { + // result += *c; + //}break; + //xwj --------------- + } + } + result += "\""; + return result; +} + +JSONCPP_STRING valueToQuotedString(const char* value) { + return valueToQuotedStringN(value, static_cast(strlen(value))); +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() {} + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + : yamlCompatibilityEnabled_(false), dropNullPlaceholders_(false), + omitEndingLineFeed_(false) {} + +void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; } + +void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } + +void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } + +JSONCPP_STRING FastWriter::write(const Value& root) { + document_.clear(); + writeValue(root); + if (!omitEndingLineFeed_) + document_ += '\n'; + return document_; +} + +void FastWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + if (!dropNullPlaceholders_) + document_ += "null"; + break; + case intValue: + document_ += valueToString(value.asLargestInt()); + break; + case uintValue: + document_ += valueToString(value.asLargestUInt()); + break; + case realValue: + document_ += valueToString(value.asDouble()); + break; + case stringValue: { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) + document_ += valueToQuotedStringN(str, static_cast(end - str)); + break; + } + case booleanValue: + document_ += valueToString(value.asBool()); + break; + case arrayValue: { + document_ += '['; + ArrayIndex size = value.size(); + for (ArrayIndex index = 0; index < size; ++index) { + if (index > 0) + document_ += ','; + writeValue(value[index]); + } + document_ += ']'; + } break; + case objectValue: { + Value::Members members(value.getMemberNames()); + document_ += '{'; + for (Value::Members::iterator it = members.begin(); it != members.end(); + ++it) { + const JSONCPP_STRING& name = *it; + if (it != members.begin()) + document_ += ','; + document_ += valueToQuotedStringN(name.data(), + static_cast(name.length())); + document_ += yamlCompatibilityEnabled_ ? ": " : ":"; + writeValue(value[name]); + } + document_ += '}'; + } break; + } +} + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() + : rightMargin_(74), indentSize_(3), addChildValues_() {} + +JSONCPP_STRING StyledWriter::write(const Value& root) { + document_.clear(); + addChildValues_ = false; + indentString_.clear(); + writeCommentBeforeValue(root); + writeValue(root); + writeCommentAfterValueOnSameLine(root); + document_ += '\n'; + return document_; +} + +void StyledWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast(end - str))); + else + pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + const JSONCPP_STRING& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + document_ += " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultilineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + writeIndent(); + writeValue(childValue); + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + document_ += "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + document_ += ", "; + document_ += childValues_[index]; + } + document_ += " ]"; + } + } +} + +bool StyledWriter::isMultilineArray(const Value& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledWriter::pushValue(const JSONCPP_STRING& value) { + if (addChildValues_) + childValues_.push_back(value); + else + document_ += value; +} + +void StyledWriter::writeIndent() { + if (!document_.empty()) { + char last = document_[document_.length() - 1]; + if (last == ' ') // already indented + return; + if (last != '\n') // Comments may add new-line + document_ += '\n'; + } + document_ += indentString_; +} + +void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) { + writeIndent(); + document_ += value; +} + +void StyledWriter::indent() { + indentString_ += JSONCPP_STRING(indentSize_, ' '); +} + +void StyledWriter::unindent() { + assert(indentString_.size() >= indentSize_); + indentString_.resize(indentString_.size() - indentSize_); +} + +void StyledWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + document_ += '\n'; + writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + document_ += *iter; + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) + writeIndent(); + ++iter; + } + + // Comments are stripped of trailing newlines, so add one here + document_ += '\n'; +} + +void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + document_ += " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + document_ += '\n'; + document_ += root.getComment(commentAfter); + document_ += '\n'; + } +} + +bool StyledWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter(const JSONCPP_STRING& indentation) + : document_(NULL), rightMargin_(74), indentation_(indentation), + addChildValues_(), indented_(false) {} + +void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) { + document_ = &out; + addChildValues_ = false; + indentString_.clear(); + indented_ = true; + writeCommentBeforeValue(root); + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *document_ << "\n"; + document_ = NULL; // Forget the stream, for safety. +} + +void StyledStreamWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast(end - str))); + else + pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + const JSONCPP_STRING& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + *document_ << " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledStreamWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultilineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *document_ << "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *document_ << ", "; + *document_ << childValues_[index]; + } + *document_ << " ]"; + } + } +} + +bool StyledStreamWriter::isMultilineArray(const Value& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *document_ << value; +} + +void StyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + *document_ << '\n' << indentString_; +} + +void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) { + if (!indented_) + writeIndent(); + *document_ << value; + indented_ = false; +} + +void StyledStreamWriter::indent() { indentString_ += indentation_; } + +void StyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) + writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *document_ << *iter; + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would include newline + *document_ << indentString_; + ++iter; + } + indented_ = false; +} + +void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + *document_ << ' ' << root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *document_ << root.getComment(commentAfter); + } + indented_ = false; +} + +bool StyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +////////////////////////// +// BuiltStyledStreamWriter + +/// Scoped enums are not available until C++11. +struct CommentStyle { + /// Decide whether to write comments. + enum Enum { + None, ///< Drop all comments. + Most, ///< Recover odd behavior of previous versions (not implemented yet). + All ///< Keep all comments. + }; +}; + +struct BuiltStyledStreamWriter : public StreamWriter { + BuiltStyledStreamWriter(JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision, + PrecisionType precisionType); + int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE; + +private: + void writeValue(Value const& value); + void writeArrayValue(Value const& value); + bool isMultilineArray(Value const& value); + void pushValue(JSONCPP_STRING const& value); + void writeIndent(); + void writeWithIndent(JSONCPP_STRING const& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(Value const& root); + void writeCommentAfterValueOnSameLine(Value const& root); + static bool hasCommentForValue(const Value& value); + + typedef std::vector ChildValues; + + ChildValues childValues_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; + CommentStyle::Enum cs_; + JSONCPP_STRING colonSymbol_; + JSONCPP_STRING nullSymbol_; + JSONCPP_STRING endingLineFeedSymbol_; + bool addChildValues_ : 1; + bool indented_ : 1; + bool useSpecialFloats_ : 1; + unsigned int precision_; + PrecisionType precisionType_; +}; +BuiltStyledStreamWriter::BuiltStyledStreamWriter( + JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision, + PrecisionType precisionType) + : rightMargin_(74), indentation_(indentation), cs_(cs), + colonSymbol_(colonSymbol), nullSymbol_(nullSymbol), + endingLineFeedSymbol_(endingLineFeedSymbol), addChildValues_(false), + indented_(false), useSpecialFloats_(useSpecialFloats), + precision_(precision), precisionType_(precisionType) {} +int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout) { + sout_ = sout; + addChildValues_ = false; + indented_ = true; + indentString_.clear(); + writeCommentBeforeValue(root); + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *sout_ << endingLineFeedSymbol_; + sout_ = NULL; + return 0; +} +void BuiltStyledStreamWriter::writeValue(Value const& value) { + switch (value.type()) { + case nullValue: + pushValue(nullSymbol_); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_, + precisionType_)); + break; + case stringValue: { + // Is NULL is possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast(end - str))); + else + pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + JSONCPP_STRING const& name = *it; + Value const& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedStringN( + name.data(), static_cast(name.length()))); + *sout_ << colonSymbol_; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value); + if (isMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + Value const& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *sout_ << "["; + if (!indentation_.empty()) + *sout_ << " "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *sout_ << ((!indentation_.empty()) ? ", " : ","); + *sout_ << childValues_[index]; + } + if (!indentation_.empty()) + *sout_ << " "; + *sout_ << "]"; + } + } +} + +bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + Value const& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *sout_ << value; +} + +void BuiltStyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + + if (!indentation_.empty()) { + // In this case, drop newlines too. + *sout_ << '\n' << indentString_; + } +} + +void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) { + if (!indented_) + writeIndent(); + *sout_ << value; + indented_ = false; +} + +void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } + +void BuiltStyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { + if (cs_ == CommentStyle::None) + return; + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) + writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *sout_ << *iter; + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would write extra newline + *sout_ << indentString_; + ++iter; + } + indented_ = false; +} + +void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine( + Value const& root) { + if (cs_ == CommentStyle::None) + return; + if (root.hasComment(commentAfterOnSameLine)) + *sout_ << " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *sout_ << root.getComment(commentAfter); + } +} + +// static +bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +/////////////// +// StreamWriter + +StreamWriter::StreamWriter() : sout_(NULL) {} +StreamWriter::~StreamWriter() {} +StreamWriter::Factory::~Factory() {} +StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); } +StreamWriterBuilder::~StreamWriterBuilder() {} +StreamWriter* StreamWriterBuilder::newStreamWriter() const { + JSONCPP_STRING indentation = settings_["indentation"].asString(); + JSONCPP_STRING cs_str = settings_["commentStyle"].asString(); + JSONCPP_STRING pt_str = settings_["precisionType"].asString(); + bool eyc = settings_["enableYAMLCompatibility"].asBool(); + bool dnp = settings_["dropNullPlaceholders"].asBool(); + bool usf = settings_["useSpecialFloats"].asBool(); + unsigned int pre = settings_["precision"].asUInt(); + CommentStyle::Enum cs = CommentStyle::All; + if (cs_str == "All") { + cs = CommentStyle::All; + } else if (cs_str == "None") { + cs = CommentStyle::None; + } else { + throwRuntimeError("commentStyle must be 'All' or 'None'"); + } + PrecisionType precisionType(significantDigits); + if (pt_str == "significant") { + precisionType = PrecisionType::significantDigits; + } else if (pt_str == "decimal") { + precisionType = PrecisionType::decimalPlaces; + } else { + throwRuntimeError("precisionType must be 'significant' or 'decimal'"); + } + JSONCPP_STRING colonSymbol = " : "; + if (eyc) { + colonSymbol = ": "; + } else if (indentation.empty()) { + colonSymbol = ":"; + } + JSONCPP_STRING nullSymbol = "null"; + if (dnp) { + nullSymbol.clear(); + } + if (pre > 17) + pre = 17; + JSONCPP_STRING endingLineFeedSymbol; + return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol, + endingLineFeedSymbol, usf, pre, + precisionType); +} +static void getValidWriterKeys(std::set* valid_keys) { + valid_keys->clear(); + valid_keys->insert("indentation"); + valid_keys->insert("commentStyle"); + valid_keys->insert("enableYAMLCompatibility"); + valid_keys->insert("dropNullPlaceholders"); + valid_keys->insert("useSpecialFloats"); + valid_keys->insert("precision"); + valid_keys->insert("precisionType"); +} +bool StreamWriterBuilder::validate(Json::Value* invalid) const { + Json::Value my_invalid; + if (!invalid) + invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set valid_keys; + getValidWriterKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + JSONCPP_STRING const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) { + return settings_[key]; +} +// static +void StreamWriterBuilder::setDefaults(Json::Value* settings) { + //! [StreamWriterBuilderDefaults] + (*settings)["commentStyle"] = "All"; + (*settings)["indentation"] = "\t"; + (*settings)["enableYAMLCompatibility"] = false; + (*settings)["dropNullPlaceholders"] = false; + (*settings)["useSpecialFloats"] = false; + (*settings)["precision"] = 17; + (*settings)["precisionType"] = "significant"; + //! [StreamWriterBuilderDefaults] +} + +JSONCPP_STRING writeString(StreamWriter::Factory const& factory, + Value const& root) { + JSONCPP_OSTRINGSTREAM sout; + StreamWriterPtr const writer(factory.newStreamWriter()); + writer->write(root, &sout); + return sout.str(); +} + +JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) { + StreamWriterBuilder builder; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + diff --git a/ExtractImageModule/CMakeLists.txt b/ExtractImageModule/CMakeLists.txt new file mode 100644 index 0000000..b7d6955 --- /dev/null +++ b/ExtractImageModule/CMakeLists.txt @@ -0,0 +1,50 @@ +#版本限定 +cmake_minimum_required (VERSION 3.5) + +set(ModuleName "ExtractImageModule") + +include(${PROJECT_SOURCE_DIR}/cmake/default_variabes.cmake) +include(${PROJECT_SOURCE_DIR}/cmake/cpp_c_flags.cmake) +include(${PROJECT_SOURCE_DIR}/cmake/print_archs.cmake) + +find_package(PkgConfig REQUIRED) +pkg_check_modules(TURBOJPEG REQUIRED libturbojpeg) + +MESSAGE(STATUS "TURBOJPEG_INCLUDE_DIRS dir " ${TURBOJPEG_INCLUDE_DIRS}) + +include_directories(${TURBOJPEG_INCLUDE_DIRS}) +link_directories(${TURBOJPEG_LIBRARY_DIRS}) +#头文件 +include_directories( +/usr/local/include + +${CMAKE_CURRENT_SOURCE_DIR}/include +) +link_directories( +/usr/local/lib/ +) +# 用set设置变量不能使用*.cpp +file(GLOB SRC_LISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) + +add_library(ExtractImage SHARED ${SRC_LISTS}) + +target_link_libraries(ExtractImage + ${OpenCV_LIBS} + ${TURBOJPEG_LIBRARIES} + ) +set(ModuleName "") + +#add_subdirectory(example) + +# make install 安装到/usr/local下 +# 自定义安装前缀 +set(CMAKE_INSTALL_PREFIX /usr/local/polet CACHE PATH "Install path prefix" FORCE) +set(HEADER_FILES include/ExtractBase.h) +# 安装动态库 +install(TARGETS ExtractImage + LIBRARY DESTINATION lib # 安装到 CMAKE_INSTALL_PREFIX/lib + ARCHIVE DESTINATION lib/static + RUNTIME DESTINATION bin + PUBLIC_HEADER DESTINATION include) # 安装到 CMAKE_INSTALL_PREFIX/include +# 安装头文件 +install(FILES ${HEADER_FILES} DESTINATION include) \ No newline at end of file diff --git a/ExtractImageModule/include/ExtractBase.h b/ExtractImageModule/include/ExtractBase.h new file mode 100644 index 0000000..8eabf53 --- /dev/null +++ b/ExtractImageModule/include/ExtractBase.h @@ -0,0 +1,25 @@ +#ifndef ExtractBase_H_ +#define ExtractBase_H_ +#include +#include +#define ExtractBaseBASE_VERSION 1 + +class ExtractBase +{ +protected: + ExtractBase() {} + +public: + // delete camera interface + ~ExtractBase() {} + static ExtractBase *GetInstance(); + // 复制想使用的参数 + virtual int ReadCELLImg(std::string strimgPath, cv::Mat &outImg, bool bdecode) = 0; + + // 返回检测版本信息 + virtual std::string GetVersion() = 0; + // 返回错误信息 + virtual std::string GetErrorInfo() = 0; +}; + +#endif \ No newline at end of file diff --git a/ExtractImageModule/include/ExtractInstance.h b/ExtractImageModule/include/ExtractInstance.h new file mode 100644 index 0000000..0ecd436 --- /dev/null +++ b/ExtractImageModule/include/ExtractInstance.h @@ -0,0 +1,73 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-09-11 15:33:10 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-13 17:07:23 + * @FilePath: /BOE_CELL_AOI_Detect/ExtractImageModule/include/ExtractInstance.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#ifndef ExtractInstance_H_ +#define ExtractInstance_H_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ExtractBase.h" +#include + +using namespace std; +namespace fs = std::filesystem; +// jpg 图片的内存指针 +struct JPGImgDataPtr +{ + unsigned char *buffer = nullptr; + size_t imgDataSize = 0; + unsigned char *ptr_start = nullptr; + unsigned char *ptr_end = nullptr; + cv::Mat decodedImg; + int width = 0; + int height = 0; + void printInfo(const std::string &name = "") const + { + std::cout << "=== JPGImgDataPtr " << name << " ===" << std::endl; + std::cout << " imgDataSize: " << imgDataSize << " bytes" << std::endl; + std::cout << " buffer: " << (buffer ? "OK" : "NULL") << std::endl; + std::cout << " buffer: " << (void *)buffer << std::endl; + std::cout << " ptr_start: " << (void *)ptr_start + << " ptr_end: " << (void *)ptr_end << std::endl; + } +}; +class ExtractInstance : public ExtractBase +{ +public: + ExtractInstance(); + ~ExtractInstance(); + + int ReadCELLImg(std::string strimgPath, cv::Mat &outImg, bool bdecode); + // 返回检测版本信息 + std::string GetVersion(); + // 返回错误信息 + std::string GetErrorInfo(); + +private: + long getcurTime(); + bool decode_Img(const std::string &file_path, cv::Mat &img); + + // 读取图片的内存地址 + int ReadImgData(const std::string &file_path, unsigned char *&buffer, size_t *fileSize); + int CalAllImgPtrDate(unsigned char *buffer, size_t fileSize, std::vector &ptrImgdataList); + int DecodeJpgImg(std::vector &ptrImgdataList, cv::Mat &outImg); + +private: +}; + +#endif \ No newline at end of file diff --git a/ExtractImageModule/src/ExtractBase.cpp b/ExtractImageModule/src/ExtractBase.cpp new file mode 100644 index 0000000..c5a48d9 --- /dev/null +++ b/ExtractImageModule/src/ExtractBase.cpp @@ -0,0 +1,15 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:50:00 + * @LastEditTime: 2022-09-26 16:27:27 + * @LastEditors: sueRimn + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/src/CamDeal.cpp + */ +#include "ExtractBase.h" +#include "ExtractInstance.h" + +ExtractBase* ExtractBase::GetInstance() +{ + return (ExtractBase*)new ExtractInstance(); +} diff --git a/ExtractImageModule/src/ExtractInstance.cpp b/ExtractImageModule/src/ExtractInstance.cpp new file mode 100644 index 0000000..328146b --- /dev/null +++ b/ExtractImageModule/src/ExtractInstance.cpp @@ -0,0 +1,322 @@ +/* + * @Author: your name + * @Date: 2022-04-20 15:50:00 + * @LastEditTime: 2025-09-13 17:12:17 + * @LastEditors: xiewenji 527774126@qq.com + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/src/CamDeal.cpp + */ +#include +#include "ExtractInstance.h" +#include +#include +#include +#include +#include +#include +#include + + +ExtractInstance::ExtractInstance() +{ +} + +ExtractInstance::~ExtractInstance() +{ +} + +int ExtractInstance::ReadImgData(const std::string &file_path, unsigned char *&buffer, size_t *fileSize) +{ + + std::ifstream file(file_path, std::ios::binary); + if (!file.is_open()) + { + std::cerr << "Error opening file!" << std::endl; + return 1; + } + + // 获取文件的大小 + file.seekg(0, std::ios::end); + size_t fileSize123 = file.tellg(); + file.seekg(0, std::ios::beg); + // printf("file size %d \n", fileSize); + // 分配内存来存储文件内容 + buffer = new unsigned char[fileSize123]; + + // 读取文件内容到内存 + file.read(reinterpret_cast(buffer), fileSize123); + file.close(); // 关闭文件 + *fileSize = fileSize123; + return 0; +} + +int ExtractInstance::CalAllImgPtrDate(unsigned char *buffer, size_t fileSize, std::vector &ptrImgdataList) +{ + + int count = 0; + int start = 0; + + // 循环提取图片,最多提取 3 张 + while (count < 3) + { + unsigned char *ptr = buffer + start; + bool found_soi = false; + bool found_eoi = false; + unsigned char *soi1 = nullptr; + unsigned char *eoi1 = nullptr; + + // 寻找SOI标记(0xFF 0xD8) + for (; ptr < buffer + fileSize - 1; ++ptr) + { + if (*ptr == 0xFF && *(ptr + 1) == 0xD8) + { + soi1 = ptr; + found_soi = true; + break; + } + } + + if (!found_soi) + break; + + // 在找结束标志时又找到了一个 开始表示。 + bool brestart = false; + // 寻找EOI标记(0xFF 0xD9) + for (ptr = soi1 + 2; ptr < buffer + fileSize - 1; ++ptr) + { + if (*ptr == 0xFF && *(ptr + 1) == 0xD9) + { + eoi1 = ptr + 2; // 包括EOI的结束部分 + found_eoi = true; + break; + } + // 在找结束标志时又找到了一个 开始表示。 + if (*ptr == 0xFF && *(ptr + 1) == 0xD8) + { + eoi1 = ptr - 1; + printf("error s %x %x -> %p \n ", *ptr, *(ptr + 1), ptr); + brestart = true; + break; + } + } + + if (brestart) + { + start = eoi1 - buffer; + continue; + } + if (!found_eoi) + break; + + size_t jpegSize = eoi1 - soi1; + + // 更新起始位置 + start = eoi1 - buffer; + + JPGImgDataPtr temdata; + temdata.buffer = buffer; + temdata.imgDataSize = jpegSize; + temdata.ptr_start = soi1; + temdata.ptr_end = eoi1; + ptrImgdataList.push_back(temdata); + + count++; + } + + return 0; +} + +int ExtractInstance::DecodeJpgImg(std::vector &ptrImgdataList, cv::Mat &outImg) +{ + + if (ptrImgdataList.empty()) + return -1; + + int commonWidth = 0; + int totalHeight = 0; + + // 第一步:读取所有头信息,检查宽度一致,累加高度 + for (auto &imgData : ptrImgdataList) + { + tjhandle handle = tjInitDecompress(); + if (!handle) + { + std::cerr << "tjInitDecompress failed!" << std::endl; + return -2; + } + + int jpegSubsamp = 0, jpegColorspace = 0; + if (tjDecompressHeader3(handle, + imgData.ptr_start, imgData.imgDataSize, + &imgData.width, &imgData.height, + &jpegSubsamp, &jpegColorspace) != 0) + { + std::cerr << "tjDecompressHeader3 error: " << tjGetErrorStr() << std::endl; + tjDestroy(handle); + return -3; + } + tjDestroy(handle); + + if (commonWidth == 0) + commonWidth = imgData.width; + else if (commonWidth != imgData.width) + { + std::cerr << "All images must have the same width!" << std::endl; + return -4; + } + + totalHeight += imgData.height; + } + + // 第二步:分配大图 + outImg = cv::Mat(totalHeight, commonWidth, CV_8UC1); + // 第三步:多线程解码到不同位置 + auto worker = [&](JPGImgDataPtr &imgData, int yOffset) + { + tjhandle handle = tjInitDecompress(); + if (!handle) + { + std::cerr << "tjInitDecompress failed!" << std::endl; + return; + } + + if (tjDecompress2(handle, + imgData.ptr_start, imgData.imgDataSize, + outImg.ptr(yOffset), imgData.width, + outImg.step, imgData.height, + TJPF_GRAY, TJFLAG_FASTDCT) != 0) + { + std::cerr << "tjDecompress2 error: " << tjGetErrorStr() << std::endl; + } + + tjDestroy(handle); + }; + + std::vector threads; + threads.reserve(ptrImgdataList.size()); + + int yOffset = 0; + for (auto &imgData : ptrImgdataList) + { + threads.emplace_back(worker, std::ref(imgData), yOffset); + yOffset += imgData.height; // 下一张图拼在下方 + } + + for (auto &t : threads) + { + if (t.joinable()) + t.join(); + } + + return 0; +} + +int ExtractInstance::ReadCELLImg(std::string strimgPath, cv::Mat &outImg, bool bdecode) +{ + int re = -1; + if(bdecode) + { + printf("ReadCELLImg========= %s \n", strimgPath.c_str()); + int re = decode_Img(strimgPath, outImg); + } + else + { + size_t lastSlashIndex = strimgPath.find_last_of("/"); + std::string basePath; + std::string pureFileName; + if (lastSlashIndex != std::string::npos) { + basePath = strimgPath.substr(0, lastSlashIndex); + pureFileName = strimgPath.substr(lastSlashIndex + 1); + } else { + pureFileName = strimgPath; + } + + // 4. 拼接出目标图片的完整路径 + std::string targetImgPath; + if (pureFileName.find("CA") != std::string::npos || pureFileName.find("CF") != std::string::npos) { + // 如果是 CA 开头,读取 CELL_CF.jpg + targetImgPath = basePath + "/CELL_CF.jpg"; + } else if (pureFileName.find("TA") != std::string::npos || pureFileName.find("TFT") != std::string::npos) { + // 如果是 TA 开头,读取 CELL_TFT.jpg + targetImgPath = basePath + "/CELL_TFT.jpg"; + } else { + std::cerr << "未知文件名: " << pureFileName << std::endl; + return -1; + } + + printf("ReadCELLImg========= %s \n", targetImgPath.c_str()); + + outImg = cv::imread(targetImgPath, cv::IMREAD_GRAYSCALE); + + // 6. 检查是否成功加载 + if (outImg.empty()) { + std::cerr << "错误:无法读取图片,请检查路径是否正确!" << std::endl; + return -1; + } + re = 0; + } + + return re; +} +std::string ExtractInstance::GetVersion() +{ + std::string str = ""; + return str; +} + +std::string ExtractInstance::GetErrorInfo() +{ + std::string str = ""; + return str; +} +bool ExtractInstance::decode_Img(const std::string &file_path, cv::Mat &img) +{ + long t1 = getcurTime(); + unsigned char *buffer = NULL; + size_t fileSize; + // 1、读入图片 + int re = ReadImgData(file_path, buffer, &fileSize); + if (re != 0 || buffer == NULL) + { + printf("error re %d buffer == NULL\n", re); + return false; + } + long t2 = getcurTime(); + + // 2、获取图片地址指针 + std::vector ptrImgdataList; + re = CalAllImgPtrDate(buffer, fileSize, ptrImgdataList); + if (re != 0 || ptrImgdataList.size() <= 0) + { + printf("error re %d size %ld \n", re, ptrImgdataList.size()); + return false; + } + long t3 = getcurTime(); + + // 3、解码 jpg 图片 + re = DecodeJpgImg(ptrImgdataList, img); + long t4 = getcurTime(); + + // printf("time %ld read %ld call ptrdata %ld decode %ld\n", t4 - t1, t2 - t1, t3 - t2, t4 - t3); + + if (re != 0 || img.empty()) + { + printf("error re %d outimg.empty()\n", re); + return false; + } + // if (true) + // { + // cv::imwrite("outimg_img11.png", outimg); + // } + // getchar(); + + delete[] buffer; + + return true; +} +long ExtractInstance::getcurTime() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return ((long)tv.tv_sec) * 1000 + ((long)tv.tv_usec) / 1000; +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..c14c1fe --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ + +# 阿加犀工业检测算法调用通用库 + +## 介绍 +京东方 检测算法so + +## 环境 +1、opencv +2、tensorRT + +## 使用 +1、把本地的TensorRT 头文件拷贝到 include文件下中。/home/aidlux/drivers/tensorrt/TensorRT-8.2.1.8/samples/common/ +2、修改模型输入、输出尺寸。ImgCheckConfig.h AI_IN_IMAGE_WIDTH AI_IN_IMAGE_HEIGHT AI_OUT_IMAGE_WIDTH AI_OUT_IMAGE_HEIGHT +3、修改模型输入参数宏定义 作为变量初始化参数 + + +### 最近更新 Update + +### Notes ++ 1、如果不能正确显示中文,有可能系统没有安装中文字符 sudo apt-get install language-pack-zh-hans + +### Author +- [谢文吉] diff --git a/cmake/cpp_c_flags.cmake b/cmake/cpp_c_flags.cmake new file mode 100644 index 0000000..1523dca --- /dev/null +++ b/cmake/cpp_c_flags.cmake @@ -0,0 +1,41 @@ +if(CMAKE_BUILD_TYPE MATCHES "(Release|RELEASE|release)") + # release mode + set(CMAKE_BUILD_TYPE "release") +else() + set(CMAKE_BUILD_TYPE "debug") + # debug mode + if(NOT (${CMAKE_C_FLAGS} MATCHES "-g")) + add_compile_options(-g) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") + endif() + if(NOT (${CMAKE_CXX_FLAGS} MATCHES "-g")) + add_compile_options(-g) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") + endif() +endif() +#--------------------------------------------------------------------------------------------------- + + +#++++++add c++11 standard and c99 standard +if(NOT (${CMAKE_C_FLAGS} MATCHES "-std=")) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") +endif() + +if(NOT (${CMAKE_CXX_FLAGS} MATCHES "-std=")) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") +endif() +#--------------------------------------------------------------------------------------------------- + + +#++++++add path of link library +if(NOT (${CMAKE_C_FLAGS} MATCHES "-Wl,-rpath,")) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-rpath,.:lib/:lib/${BUILD_ARCH}/:../lib/${BUILD_ARCH}/:../lib/${BUILD_ARCH}/HK/:../lib/${BUILD_ARCH}/HK/HCNetSDKCom") +endif() + +if(NOT (${CMAKE_CXX_FLAGS} MATCHES "-Wl,-rpath,")) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-rpath,.:lib/:lib/${BUILD_ARCH}/:../lib/${BUILD_ARCH}/:../lib/${BUILD_ARCH}/HK/:../lib/${BUILD_ARCH}/HK/HCNetSDKCom") +endif() +#--------------------------------------------------------------------------------------------------- + +# message(STATUS "CMAKE_CXX_FLAGS:${CMAKE_CXX_FLAGS}") \ No newline at end of file diff --git a/cmake/default_variabes.cmake b/cmake/default_variabes.cmake new file mode 100644 index 0000000..d685cd3 --- /dev/null +++ b/cmake/default_variabes.cmake @@ -0,0 +1,15 @@ +if(NOT DEFINED ModuleName OR ModuleName EQUAL "") + set(ModuleName "DefaultModule") +endif() + +# BUILD_ARCH:x86_64 aarch64 参考 gcc -v 结果的 Target +if(NOT DEFINED BUILD_ARCH) + set(BUILD_ARCH x86_64 CACHE STRING "Arch of this project") +endif() + +if(NOT "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}" STREQUAL "${CMAKE_BINARY_DIR}/../lib/${BUILD_ARCH}/") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/${BUILD_ARCH}/) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/${BUILD_ARCH}/) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/) +endif() +link_directories(${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) \ No newline at end of file diff --git a/cmake/print_archs.cmake b/cmake/print_archs.cmake new file mode 100644 index 0000000..008ba76 --- /dev/null +++ b/cmake/print_archs.cmake @@ -0,0 +1,2 @@ +message(STATUS "build <${ModuleName}>") +message(STATUS " ARCH type:${BUILD_ARCH} Mode:${CMAKE_BUILD_TYPE}") \ No newline at end of file diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 0000000..e5dbb8d --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1,42 @@ +cmake_minimum_required (VERSION 3.5) +find_package( OpenCV REQUIRED ) + +message(STATUS "oPENCV Library status:") +message(STATUS ">version:${OpenCV_VERSION}") +message(STATUS "Include:${OpenCV_INCLUDE_DIRS}") + + +set(CMAKE_CXX_STANDARD 17) + +set(CMAKE_CXX_FLAGS "-Wno-error=deprecated-declarations -Wno-deprecated-declarations") + +include_directories( +${CMAKE_CURRENT_SOURCE_DIR}/include +${PROJECT_SOURCE_DIR}/AlgorithmModule/include +${PROJECT_SOURCE_DIR}/ConfigModule/include +${PROJECT_SOURCE_DIR}/ExtractImageModule/include +) + +link_directories( +/usr/local/lib/ +/usr/local/cuda/lib64 +) +file(GLOB SRC_LISTS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) + +add_executable("test_CellAOI" ${SRC_LISTS}) + +target_link_libraries("test_CellAOI" + pthread + z + nvinfer + TY_Check + Config + ExtractImage + #/usr/local/cuda-12.1/targets/x86_64-linux/lib/libcudart.so + ${OpenCV_LIBS} +) +# 设置该目标的RPATH +set_target_properties("test_CellAOI" PROPERTIES + BUILD_RPATH "\$ORIGIN" +) +set(ModuleName "") \ No newline at end of file diff --git a/example/CheckDefine.h b/example/CheckDefine.h new file mode 100644 index 0000000..789b163 --- /dev/null +++ b/example/CheckDefine.h @@ -0,0 +1,48 @@ +/* + * @Descripttion: + * @version: + * @Author: sueRimn + * @Date: 2022-03-16 17:09:11 + * @LastEditors: sueRimn + * @LastEditTime: 2022-09-23 17:43:15 + */ + +#ifndef _CheckDefine_HPP_ +#define _CheckDefine_HPP_ + +#include + +#define SRC_IMAGE_WIDTH 14192 +#define SRC_IMAGE_HEIGHT 10640 + +#define SRC_IMAGE_SIZE 1*SRC_IMAGE_WIDTH *SRC_IMAGE_HEIGHT + +#define AI_BATCH_SIZE 1 + + +enum ERRORDEFINE +{ + RESULT_OK, + ERROR_CHECK_IMG_NULL, // 检测图片为空 + ERROR_CHECK_RESOURCE_NULL, // 检测资源为空 + ERROR_PRECHECK_IMG_NULL, // 预检测图片 异常 + +}; +// 检测控制参数 +struct CheckControlConfigSt +{ + CheckControlConfigSt() + { + } +}; +// 系统运行控制参数 +struct SystmeControlConfigST +{ + CheckControlConfigSt checkControlConfig; //// 检测控制参数 + + SystmeControlConfigST() + { + } +}; + +#endif //_CORELOGICFACTORY_HPP_ \ No newline at end of file diff --git a/example/Image_ReadAndChange.cpp b/example/Image_ReadAndChange.cpp new file mode 100644 index 0000000..d752432 --- /dev/null +++ b/example/Image_ReadAndChange.cpp @@ -0,0 +1,129 @@ +#include "Image_ReadAndChange.h" +#include "json/json.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +Image_ReadChannel::Image_ReadChannel() +{ + m_ChannelNameList.clear(); +} + +Image_ReadChannel::~Image_ReadChannel() +{ +} +bool Image_ReadChannel::containsChinese(const std::string &str) +{ + for (size_t i = 0; i < str.size(); ++i) + { + if ((unsigned char)str[i] >= 0x80) + { + return true; // 如果有非ASCII字符(可能是中文) + } + } + return false; +} +bool Image_ReadChannel::CompareIgnoreCase(const std::string &str1, const std::string &str2) +{ + // 将 str1 和 str2 转换为小写后进行比较 + std::string lower_str1 = str1; + std::string lower_str2 = str2; + + // 使用 std::transform 将字符串转换为小写 + std::transform(lower_str1.begin(), lower_str1.end(), lower_str1.begin(), ::tolower); + std::transform(lower_str2.begin(), lower_str2.end(), lower_str2.begin(), ::tolower); + + // 比较两个转换后的字符串 + return lower_str1 == lower_str2; +} +int Image_ReadChannel::ReadJsonConfig(std::string json_path) +{ + m_ChannelNameList.erase(m_ChannelNameList.begin(), m_ChannelNameList.end()); + std::string strPath = json_path; + printf("ReadJsonConfig path %s\n", strPath.c_str()); + Json::CharReaderBuilder builder; + builder["collectComments"] = true; + Json::Value root; + std::string err; + std::ifstream ifs(strPath); + if (!ifs.is_open()) + { + printf("error:file is open\n"); + return false; + } + if (!Json::parseFromStream(builder, ifs, &root, &err)) + { + printf("error:parseFromStream\n"); + return false; + } + + for (int i = 0; i < root.size(); i++) + { + // printf("Node idx %d /%d \n", i, root.size()); + + ReadImageName tem; + tem.strDetChannle = root[i]["code"].asString(); + std::string strimgname = root[i]["image_name"].asString(); + { + + std::istringstream stream(strimgname); + std::string token; + + // 使用 getline 按照分号分割 + while (std::getline(stream, token, ';')) + { + tem.strImgNameList.push_back(token); + } + } + // printf("det name %s img name Num %ld \n", tem.strDetChannle.c_str(), tem.strImgNameList.size()); + // 输出分割后的结果 + // for (const auto &str : tem.strImgNameList) + // { + // std::cout << str << std::endl; + // } + + m_ChannelNameList.push_back(tem); + } + + return 0; +} + +std::string Image_ReadChannel::strDetName(std::string strImageName) +{ + std::string strDetName = ""; + for (const auto name : m_ChannelNameList) + { + + for (int i = 0; i < name.strImgNameList.size(); i++) + { + // 包含中文 + if (containsChinese(strImageName)) + { + // printf("strImageName %s name.strImgNameList.at(i) %s\n",strImageName.c_str(), name.strImgNameList.at(i).c_str()); + if (strImageName == name.strImgNameList.at(i)) + { + return name.strDetChannle; + } + } + else + { + if (CompareIgnoreCase(strImageName, name.strImgNameList.at(i))) + { + return name.strDetChannle; + } + } + } + } + + return strDetName; +} diff --git a/example/Image_ReadAndChange.h b/example/Image_ReadAndChange.h new file mode 100644 index 0000000..6b21191 --- /dev/null +++ b/example/Image_ReadAndChange.h @@ -0,0 +1,56 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-07-25 09:14:25 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-11 18:00:27 + * @FilePath: /BOE_CELL_ET/AlgorithmModule/example/Image_ReadAndChange.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/* +//图片基本处理 + */ +#ifndef Image_ReadAndChange_H_ +#define Image_ReadAndChange_H_ + +#include +#include +#include "CheckDefine.h" +#include "ImgCheckConfig.h" +using namespace std; + + +// 图片读取的通道 +class Image_ReadChannel +{ +public: + struct ReadImageName + { + std::string strDetChannle; + std::vector strImgNameList; + + ReadImageName() + { + strImgNameList.clear(); + strDetChannle = ""; + } + }; + +private: + /* data */ +public: + Image_ReadChannel(/* args */); + ~Image_ReadChannel(); + + bool containsChinese(const std::string &str); + + int ReadJsonConfig(std::string json_path); // 加载检测图片名称配置参数 + + bool CompareIgnoreCase(const std::string &str1, const std::string &str2); + + std::string strDetName(std::string strImageName); + +private: + std::vector m_ChannelNameList; +}; + +#endif \ No newline at end of file diff --git a/example/JsonCoversion.cpp b/example/JsonCoversion.cpp new file mode 100644 index 0000000..13c1478 --- /dev/null +++ b/example/JsonCoversion.cpp @@ -0,0 +1,35 @@ +#include "JsonCoversion.h" + +JsonCoversion::JsonCoversion() +{ + //ctor +} + +JsonCoversion::~JsonCoversion() +{ + //dtor +} +string JsonCoversion::toJson() +{ + toJsonValue(); + + std::unique_ptr jsonWriter(writerBuilder.newStreamWriter()); + std::ostringstream os; + std::string jsonStr; + jsonWriter->write(root,&os); + jsonStr = os.str(); + return jsonStr; +} + +void JsonCoversion::toObject(string & strBuf) +{ + std::unique_ptr const jsonReader(readerBuilder.newCharReader()); + + JSONCPP_STRING errs; + bool res = jsonReader->parse(strBuf.c_str(), strBuf.c_str()+strBuf.length(), &root, &errs); + if (!res || !errs.empty()) + { + std::cout << "parseJson err. " << errs << std::endl; + } + toObjectFromValue(root); +} diff --git a/example/JsonCoversion.h b/example/JsonCoversion.h new file mode 100644 index 0000000..5419e33 --- /dev/null +++ b/example/JsonCoversion.h @@ -0,0 +1,31 @@ +#ifndef JsonCoversion_H +#define JsonCoversion_H +#include +#include +#include +#include "json/json.h" +using namespace std; + +class JsonCoversion +{ + protected: + Json::Value root; + + // Json::FastWriter writer; //弃用 改用StreamWriterBuilder + Json::StreamWriterBuilder writerBuilder; + + // Json::Reader reader; //弃用 改用CharReaderBuilder + Json::CharReaderBuilder readerBuilder; + public: + JsonCoversion(); + virtual ~JsonCoversion(); + protected: + public: + string toJson(); + void toObject(string & strBuf); + protected: + virtual Json::Value toJsonValue() = 0; + virtual void toObjectFromValue(Json::Value root) = 0; +}; + +#endif // JsonCoversion_H diff --git a/example/Read_Image.cpp b/example/Read_Image.cpp new file mode 100644 index 0000000..973c875 --- /dev/null +++ b/example/Read_Image.cpp @@ -0,0 +1,287 @@ +#include "Read_Image.h" +#include +// 转小写 +std::string toLower(const std::string &str) +{ + std::string lower = str; + std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower); + return lower; +} + +int Extract_Name_Base::Read_Product_Image(std::string strPath) +{ + + return 0; +} + +int Extract_Name_Base::Read_Camera_Product_Image(std::string strPath, int userflag, std::string strproduct) +{ + + std::vector img_paths; + // std::cout << strPath << std::endl; + cv::glob(strPath, img_paths, true); + for (int i = 0; i < img_paths.size(); i++) + { + string strImagePath = img_paths[i]; + Extract_Info(strImagePath, strproduct, userflag); + } + + return 0; +} + +int Extract_Name_Base::Read_Product_Camera_Image(std::string strPath) +{ + return 0; +} + +std::shared_ptr Extract_Name_Base::GetProduct(std::string strProductID) +{ + for (int i = 0; i < m_product_Camera_List.size(); i++) + { + if (m_product_Camera_List[i]->strProductID == strProductID) + { + return m_product_Camera_List[i]; + } + } + return std::shared_ptr(); +} + +std::shared_ptr Extract_Name_Base::GetCamera(std::string strProductID, std::string strCamName) +{ + for (int i = 0; i < m_product_Camera_List.size(); i++) + { + if (m_product_Camera_List[i]->strProductID == strProductID) + { + for (int j = 0; j < m_product_Camera_List[i]->camera_list.size(); j++) + { + if (m_product_Camera_List[i]->camera_list[j]->strCamName == strCamName) + { + return m_product_Camera_List[i]->camera_list[j]; + } + } + } + } + return std::shared_ptr(); +} + +std::shared_ptr Extract_Name_Base::GetCamera(std::shared_ptr product, std::string strCamName) +{ + for (int i = 0; i < product->camera_list.size(); i++) + { + if (product->camera_list[i]->strCamName == strCamName) + { + return product->camera_list[i]; + } + } + return std::shared_ptr(); +} + +// 判断目录部分是否包含某些关键词(不区分大小写) +bool Extract_Name_Base::dirPathContains(const fs::path &fullPath, const std::string KeyName) +{ + fs::path parentDir = fullPath.parent_path(); + std::string lowKeyName = toLower(KeyName); + for (const auto &dir : parentDir) + { + std::string dirName = toLower(dir.string()); + + if (dirName == lowKeyName) + { + return true; + } + } + + return false; +} + +Read_Image::Read_Image(/* args */) +{ +} + +Read_Image::~Read_Image() +{ +} + +int Read_Image::Read_Image_List(std::string strPath, std::string strproduct) +{ + m_extract.pimage_ReadChannel = pimage_ReadChannel; + m_extract.m_product_Camera_List.clear(); + int re = m_extract.Read_Image_List(strPath, strproduct); + if (re != 0) + { + return re; + } + m_product_Camera_List.clear(); + m_product_Camera_List.assign(m_extract.m_product_Camera_List.begin(), m_extract.m_product_Camera_List.end()); + + for (int i = 0; i < m_extract.m_product_Camera_List.size(); i++) + { + m_extract.m_product_Camera_List[i]->print(); + } + return 0; +} + +int Read_Image::Read_Image_List(std::string strPath_left, std::string strPath_right, std::string strproduct) +{ + m_extract.pimage_ReadChannel = pimage_ReadChannel; + m_extract.m_product_Camera_List.clear(); + int re = m_extract.Read_Image_List(strPath_left, strPath_right, strproduct); + if (re != 0) + { + return re; + } + m_product_Camera_List.clear(); + m_product_Camera_List.assign(m_extract.m_product_Camera_List.begin(), m_extract.m_product_Camera_List.end()); + + for (int i = 0; i < m_extract.m_product_Camera_List.size(); i++) + { + m_extract.m_product_Camera_List[i]->print(); + } + return 0; +} + +int Extract_ALL::Extract_Info(std::string strPath, std::string strproduct, int userflag) +{ + // std::cout << strPath << std::endl; + // 1、获取 产品名称 + std::string strProductName = Extract_Product_Name(strPath, userflag); + if (strProductName.empty()) + { + return -1; + } + + std::shared_ptr pProduct = GetProduct(strProductName); + if (strproduct != "" && strproduct != strProductName) + { + return -2; + } + + if (pProduct.get() == nullptr) + { + printf("pProduct %s is NULL \n", strProductName.c_str()); + pProduct = std::make_shared(); + pProduct->strProductID = strProductName; + m_product_Camera_List.push_back(pProduct); + } + // 2、获取 相机名称 + std::string strCameraName = Extract_Camera_Name(strPath, userflag); + if (strCameraName.empty()) + { + printf("strCameraName is error \n"); + return -1; + } + std::shared_ptr pCamera = GetCamera(pProduct, strCameraName); + if (pCamera.get() == nullptr) + { + printf("pCamera %s is NULL \n", strCameraName.c_str()); + pCamera = std::make_shared(); + pCamera->strCamName = strCameraName; + pProduct->camera_list.push_back(pCamera); + } + + // 3、获取 通道 + std::string strChannelName = Extract_Channel_Name(strPath, userflag); + if (strChannelName.empty()) + { + printf("strChannelName is NULL \n"); + return -1; + } + fs::path p = fs::path(strPath); + std::string filenameWithoutExt = p.stem().string(); + + std::shared_ptr pImage = std::make_shared(); + + pImage->strProductID = strProductName; + pImage->strCamID = strCameraName; + pImage->strchannelName = strChannelName; + pImage->strName = filenameWithoutExt; + pImage->strPath = strPath; + pCamera->image_list.push_back(pImage); + + return 0; +} + +std::string Extract_ALL::Extract_Camera_Name(std::string strPath, int userflag) +{ + + fs::path p = fs::path(strPath); + std::string filename = p.stem(); + if (filename.find("TA") != std::string::npos) + return "TA"; + else if (filename.find("CA") != std::string::npos) + return "CA"; + + // std::cout << "完整路径: " << p << std::endl; + // std::cout << "文件名: " << p.filename() << std::endl; + // std::cout << "不带后缀的文件名: " << p.stem() << std::endl; + // std::cout << "后缀: " << p.extension() << std::endl; + // getchar(); + + return ""; +} + +std::string Extract_ALL::Extract_Product_Name(std::string strPath, int userflag) +{ + + // std::cout << strPath << std::endl; + fs::path p = fs::path(strPath); + fs::path lastDir = p.parent_path().filename(); + + std::string name = lastDir.string(); + if (name.length()<7) + { + lastDir = p.parent_path().parent_path().filename(); + name = lastDir.string(); + } + + // std::cout << name << std::endl; + if (name.empty()) + { + return ""; + } + + return name; +} + +std::string Extract_ALL::Extract_Channel_Name(std::string strPath, int userflag) +{ + std::string strchannelName = ""; + fs::path p = fs::path(strPath); + std::string filename = p.stem(); + if (filename.find("TAA") != std::string::npos) + strchannelName = "TA"; + else if (filename.find("TAB") != std::string::npos) + strchannelName = "TA"; + else if (filename.find("CAA") != std::string::npos) + strchannelName = "CA"; + else if (filename.find("CAB") != std::string::npos) + strchannelName = "CA"; + else if (filename.find("CA") != std::string::npos) + strchannelName = "CA"; + else if (filename.find("TA") != std::string::npos) + strchannelName = "TA"; + return strchannelName; +} +int Extract_ALL::Read_Image_List(std::string strPath, std::string strproduct) +{ + std::string strSearchImgPath = strPath + "/*.ytimage"; + Read_Camera_Product_Image(strSearchImgPath, 0, strproduct); + + // strSearchImgPath = strPath + "/*.png"; + // Read_Camera_Product_Image(strSearchImgPath, 1); + + return 0; +} + +int Extract_ALL::Read_Image_List(std::string strPath_left, std::string strPath_right, std::string strproduct) +{ + std::string strSearchImgPath = strPath_left + "/*.ytimage"; + Read_Camera_Product_Image(strSearchImgPath, 0, strproduct); + strSearchImgPath = strPath_right + "/*.ytimage"; + Read_Camera_Product_Image(strSearchImgPath, 0, strproduct); + + // strSearchImgPath = strPath + "/*.png"; + // Read_Camera_Product_Image(strSearchImgPath, 1); + + return 0; +} diff --git a/example/Read_Image.h b/example/Read_Image.h new file mode 100644 index 0000000..0265f62 --- /dev/null +++ b/example/Read_Image.h @@ -0,0 +1,185 @@ + +#ifndef Read_Image_HPP_ +#define Read_Image_HPP_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Image_ReadAndChange.h" + +namespace fs = std::filesystem; +using namespace std; + +// 图片信息 +struct Image_Info +{ + std::string strProductID; // 产品ID + std::string strCamID; // 相机名称 + std::string strchannelName; // 通道名称 + std::string strPath; // 完整路径 + std::string strName; // 图片名称 + cv::Mat img; // 图像数据 + long readImg_start; // 读取开始时间 + long readImg_end; // 读取结束时间 + + // 构造函数,调用 Init 初始化 + Image_Info() + { + Init(); + } + + // 初始化函数,重置所有成员变量 + void Init() + { + strProductID = ""; + strCamID = ""; + strchannelName = ""; + strPath = ""; + strName = ""; + img.release(); // 释放图像内存 + readImg_start = 0; + readImg_end = 0; + } + + void print() + { + std::cout << "Product ID: " << strProductID << std::endl; + std::cout << "Camera ID: " << strCamID << std::endl; + std::cout << "Channel Name: " << strchannelName << std::endl; + std::cout << "Image Path: " << strPath << std::endl; + std::cout << "Image Name: " << strName << std::endl; + std::cout << "Read Start Time: " << readImg_start << std::endl; + std::cout << "Read End Time: " << readImg_end << std::endl; + } +}; + +// 相机信息 +struct Camera_File_Info +{ + std::string strCamName; // 相机名称 + std::string strCamPath; // 相机路径 + vector> image_list; // 图片信息列表 + Camera_File_Info() + { + Init(); + } + void Init() + { + strCamName = ""; + strCamPath = ""; + } + int getImgNum() + { + int num = 0; + for (auto item : image_list) + { + num++; + } + return num; + } + void print() + { + printf("************CamName: %s img num %ld\n", strCamName.c_str(), image_list.size()); + // for (auto &item : image_list) + // { + // // item->print(); + // } + } +}; +// 产品信息 +struct Product_File_Info +{ + std::string strProductID; // 产品ID + std::string strProductPath; // 产品路径 + vector> camera_list; // 相机信息列表 + Product_File_Info() + { + Init(); + } + void Init() + { + strProductID = ""; + strProductPath = ""; + } + int getImgNum() + { + int num = 0; + for (auto item : camera_list) + { + num += item->getImgNum(); + } + return num; + } + void print() + { + printf("***strProductID: %s\n", strProductID.c_str()); + for (auto &item : camera_list) + { + item->print(); + } + } +}; +class Extract_Name_Base +{ +public: + virtual int Extract_Info(std::string strPath, std::string strproduct, int userflag) = 0; + virtual std::string Extract_Camera_Name(std::string strPath, int userflag = 0) = 0; + virtual std::string Extract_Product_Name(std::string strPath, int userflag = 0) = 0; + virtual std::string Extract_Channel_Name(std::string strPath, int userflag = 0) = 0; + virtual int Read_Image_List(std::string strPath, std::string strproduct) = 0; + virtual int Read_Image_List(std::string strPath_left, std::string strPath_right, std::string strproduct) = 0; + int Read_Product_Image(std::string strPath); + int Read_Camera_Product_Image(std::string strPath, int userflag, std::string strproduct); + int Read_Product_Camera_Image(std::string strPath); + std::shared_ptr GetProduct(std::string strProductID); + std::shared_ptr GetCamera(std::string strProductID, std::string strCamName); + std::shared_ptr GetCamera(std::shared_ptr product, std::string strCamName); + + bool dirPathContains(const fs::path &fullPath, const std::string KeyName); + + vector> m_product_Camera_List; + Image_ReadChannel *pimage_ReadChannel; +}; + +class Extract_ALL : public Extract_Name_Base +{ +public: + int Extract_Info(std::string strPath, std::string strproduct, int userflag = 0); + std::string Extract_Camera_Name(std::string strPath, int userflag = 0); + std::string Extract_Product_Name(std::string strPath, int userflag = 0); + std::string Extract_Channel_Name(std::string strPath, int userflag = 0); + int Read_Image_List(std::string strPath, std::string strproduct); + int Read_Image_List(std::string strPath_left, std::string strPath_right, std::string strproduct); +}; +class Read_Image +{ +public: + // 图片文件的格式 + enum Image_File_TYPE_ + { + Image_File_Product_Image, // 产品-图片格式 + Image_File_Camera_Product_Image, // 相机-产品-图片格式 + Image_File_Product_Camera_Image, // 产品-相机-图片格式 + }; + +public: + Read_Image(/* args */); + ~Read_Image(); + + int Read_Image_List(std::string strPath, std::string strproduct); + int Read_Image_List(std::string strPath_left, std::string strPath_right, std::string strproduct); + Extract_ALL m_extract; + + Image_ReadChannel *pimage_ReadChannel; + +private: +public: + vector> m_product_Camera_List; // 产品相机列表 +}; + +#endif \ No newline at end of file diff --git a/example/SystemCommonDefine.h b/example/SystemCommonDefine.h new file mode 100644 index 0000000..fda622a --- /dev/null +++ b/example/SystemCommonDefine.h @@ -0,0 +1,163 @@ +/* + * @Descripttion: + * @version: + * @Author: sueRimn + * @Date: 2022-03-16 17:09:11 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-09-11 18:16:45 + */ + +#ifndef _SYSTEMCOMMONDEFIN1_HPP_ +#define _SYSTEMCOMMONDEFIN1_HPP_ +#include +// working:”检测”, ready:”就绪”, check: “自检”, bad: “故障”, close: “关闭” +// 系统运行状态定义 +enum SYSTEMRUNTYPE_ +{ + SYSTEM_RUN_TYPE_null, + SYSTEM_RUN_TYPE_working, // ”检测” + SYSTEM_RUN_TYPE_ready, // ”就绪” + SYSTEM_RUN_TYPE_check, // “自检” + SYSTEM_RUN_TYPE_bad, // “故障” + SYSTEM_RUN_TYPE_close, // “关闭” + SYSTEM_RUN_TYPE_count, +}; +// + +// 检测状态 离线检测 在线检测 +enum CHECKIMGTRUNTYP_ +{ + CHECK_TYPE_ONLING, // 在线检测 + CHECK_TYPE_OFFLING, // 离线检测 + +}; + + +//------------------------config file define---------------------------------------- + +#define FILE_SYSTEM_RUN_CONFIG "../data/system_param.json" + +#define FILE_THRESHOLDPARARM "/var/aidlux/efs/jdf/model/param.json" +#define FILE_CAM_ROI_PARARM "/var/aidlux/aid-cms/model/roi.json" +#define FILE_AIMODEL_FILE_PATH "/var/aidlux/aid-cms/model/config.json" +#define FILE_CONFIG_ROOR_PATH "/var/aidlux/aid-cms/model/" + +#define FILE_AI_defect_BOE_MODEL_PATH "/home/aidlux/BOE/UseModel/defect.engine" +#define FILE_AI_classis_BOE_MODEL_PATH "/home/aidlux/BOE/UseModel/class.engine" + +#define FILE_CHECKIMG_CONFIG "../DataConfig/check_Config.ini" + +#define FILE_SAVEOKIMG_PATH "/home/aidlux/xwj/OKImg/" + +// #define FILE_SAVEALLIMG_PATH "/home/aidlux/JBL/imageData/" +#define FILE_SAVEALLIMG_PATH "/ssd/SaveImg/" +#define FILE_SAVENGIMG_PATH "/ssd/NGImg/" + +// #define MAX_NAM_LEN 64 + +// 字符长度 +#define MAX_STR_LEN 128 +// url长度 +#define MAX_ULR_LEN 256 + +#define MAX_GPU_NUM 2 + +// ncnn 行人检测 跟踪 检测最大 线程个数 +#define MAX_PERSONTRACKER_THREAD_NUM 4 + +// 共享内存检测最大 线程个数 +#define MAX_SHARMEMORYCHECK_THREAD_NUM 2 + +// 行人+跌倒检测 算法 资源 起止 +#define SHARMEMORYCHECK_THREAD_PERSON_IDX_START 0 +#define SHARMEMORYCHECK_THREAD_PERSON_IDX_END 6 + +// 离岗行人 算法 资源 起止 +#define SHARMEMORYCHECK_THREAD_Departure_PERSON_IDX_START 7 +#define SHARMEMORYCHECK_THREAD_Departure_PERSON_IDX_END 7 + +// 属性检测 算法 资源 起止 +#define SHARMEMORYCHECK_THREAD_ATTRIBUTE_IDX_START 9 +#define SHARMEMORYCHECK_THREAD_ATTRIBUTE_IDX_END 9 + +#define USERSHAREKEY 476550 + +#define SHARED_MEM_LEN IMAGE_WIDTH *IMAGE_HEIGHT * 3 + +#define HTTP_SERVER_PATTERN_CAMCONFIG "/api/camera/param" +#define HTTP_SERVER_PATTERN_CAMCHECKROI "/api/camera/roi" +#define HTTP_SERVER_PATTERN_PARAM_ADD "/param/add" +#define HTTP_SERVER_PATTERN_PREVIEW "/preview" +#define HTTP_SERVER_PATTERN_SWITCH "/switch" +#define HTTP_SERVER_PATTERN_DETECT_OPEN_ALL "/api/detect/open/all" +#define HTTP_SERVER_PATTERN_PLC_STATE "/api/plc/state" +#define HTTP_SERVER_PATTERN_PLC_SET_STATE "/api/plc/set/state" + +#define IMAGE_SIZE (2048 * 1792) + +enum START_SYSTEM_STEP_ +{ + START_SYSTEM_STEP_LoadConfig, + START_SYSTEM_STEP_InitCheck, + START_SYSTEM_STEP_PreCheck, + START_SYSTEM_STEP_CamIO, + START_SYSTEM_STEP_Complete, +}; +struct SystemConfigParam +{ + std::string Analysis_Config_path; + std::string Analysis_Config_path_Cam2; + std::string Check_Config_path; + std::string config_Root_Path; + + std::string preCheckImg_Path; // 预处理图片 + int Use_CPU_StartIdx; // 使用 CPU的开始核 + int preCHeck_YX; // 异显检测 : 1 :用异显1模型 检测; 2:用异显2模型 检测; 其他:不进行异显检测 + int preCHeck_defect; // 缺陷检测模型,1:用wtb btw hb4 等进检测; 其他 用模型进行检测 + SystemConfigParam() + { + Use_CPU_StartIdx = 0; + preCheckImg_Path = "../data/t1.tif"; + preCHeck_YX = 0; + preCHeck_defect = 0; + config_Root_Path = ""; + } + bool valid() + { + if (Analysis_Config_path.size() && + Check_Config_path.size() && + preCheckImg_Path.size() && + config_Root_Path.size() && + Use_CPU_StartIdx >= 0) + { + return true; + } + return false; + } +}; + +enum THREAD_CPU_ +{ + THREAD_CPU_Main_Det, + THREAD_CPU_Main_readImg, + THREAD_CPU_Main_saveImg, + THREAD_CPU_CheckSo, + THREAD_CPU_Count, +}; + +struct CPU_ID_INFO_ +{ + int startIdx; + int num; + CPU_ID_INFO_() + { + startIdx = 0; + num = 0; + } + void set(int sidx, int num) + { + this->startIdx = sidx; + this->num = num; + } +}; +#endif //_CORELOGICFACTORY_HPP_ \ No newline at end of file diff --git a/example/deal.cpp b/example/deal.cpp new file mode 100644 index 0000000..151844c --- /dev/null +++ b/example/deal.cpp @@ -0,0 +1,2612 @@ +#include "deal.h" +#include "json/json.h" +#include +#include +#include +#include +#include +#include "CheckUtil.hpp" +std::string ExtractFileNameWithoutExtension(const std::string &strImgPath) +{ + // 查找最后一个斜杠 '/' 或 '\' 的位置 + size_t lastSlashPos = strImgPath.find_last_of("/\\"); + + // 如果没有找到斜杠,默认整个字符串是文件名 + std::string fileName = (lastSlashPos == std::string::npos) + ? strImgPath + : strImgPath.substr(lastSlashPos + 1); + // 查找最后一个点 '.' 的位置 + size_t lastDotPos = fileName.find_last_of('.'); + // 如果没有找到点号,或者点号在第一个字符的位置,则返回完整文件名 + if (lastDotPos == std::string::npos || lastDotPos == 0) + { + return fileName; + } + + // 返回去掉扩展名的部分 + return fileName.substr(0, lastDotPos); +} +std::string GetFileName(const std::string &strImgPath) +{ + // 查找最后一个斜杠 '/' 或 '\' 的位置 + size_t lastSlashPos = strImgPath.find_last_of("/\\"); + + // 如果没有找到斜杠,默认整个字符串是文件名 + std::string fileName = (lastSlashPos == std::string::npos) + ? strImgPath + : strImgPath.substr(lastSlashPos + 1); + // 查找最后一个点 '.' 的位置 + + return fileName; +} +bool customSort(const AI_Det_Channel_ &a, const AI_Det_Channel_ &b) +{ + // 特定规则排序: "a" 排第一, "b" 排第二, "L" 排最后 + if (a.strChannel == "Up-Particle" && b.strChannel != "Up-Particle") + { + return true; // "a" 排在前面 + } + if (a.strChannel != "Up-Particle" && b.strChannel == "Up-Particle") + { + return false; + } + + if (a.strChannel == "Down-Particle" && b.strChannel != "Down-Particle" && b.strChannel != "Up-Particle") + { + return true; // "b" 排第二 + } + if (a.strChannel != "Down-Particle" && b.strChannel == "Down-Particle") + { + return false; + } + + if (a.strChannel == "L0" && b.strChannel != "L0" && b.strChannel != "Up-Particle" && b.strChannel != "Down-Particle") + { + return false; // "L" 排最后 + } + if (a.strChannel != "L0" && b.strChannel == "L0") + { + return true; + } + + // 对其他情况使用字典顺序排序 + return a.strChannel < b.strChannel; +} + +// 定义图片读取函数 +void readImage(const std::string &filename) +{ + cv::Mat image = cv::imread(filename); + if (image.empty()) + { + std::cerr << "Error: Unable to read image " << filename << std::endl; + return; + } + + // // 在这里可以添加对图像的处理操作 + // // 例如:显示图像、保存图像、进行其他处理等 + + // // 示例:显示图像 + // cv::imshow(filename, image); + // cv::waitKey(0); + // cv::destroyWindow(filename); +} + +int _sysmkdir_1(const std::string &dir) +{ + int ret = mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if (ret && errno == EEXIST) + { + // printf("dir[%s] already exist.\n", dir.c_str()); + } + else if (ret) + { + printf("create dir[%s] error: %d %s\n", dir.c_str(), ret, strerror(errno)); + return -1; + } + else + { + printf("create dir[%s] success.\n", dir.c_str()); + } + return 0; +} +std::string __getParentDir_1(const std::string &dir) +{ + std::string pdir = dir; + if (pdir.length() < 1 || (pdir[0] != '/')) + { + return ""; + } + while (pdir.length() > 1 && (pdir[pdir.length() - 1] == '/')) + pdir = pdir.substr(0, pdir.length() - 1); + + pdir = pdir.substr(0, pdir.find_last_of('/')); + return pdir; +} +int _sysmkdirs_1(const std::string &dir) +{ + int ret = 0; + if (dir.empty()) + return -1; + std::string pdir; + if ((ret = _sysmkdir_1(dir)) == -1) + { + pdir = __getParentDir_1(dir); + if ((ret = _sysmkdirs_1(pdir)) == 0) + { + ret = _sysmkdirs_1(dir); + } + } + + return ret; +} + +long getcurTime() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return ((long)tv.tv_sec) * 1000 + ((long)tv.tv_usec) / 1000; +} +deal::deal() +{ + nLastCheckAnalysisyThreadIdx = 0; + m_nCamIdx = 0; + m_nCurUseCPUIDX = 0; + m_nSaveDetprocessImg = 0; + m_DetResult.Init(); + for (int i = 0; i < READ_IMG_THREAD_NUM; i++) + { + m_nReadStausList[i] = ReadImg_Status_IDE; + } + m_nreadImg_Stop = false; + m_strCurDate = ""; + m_nReadThread_type = READ_THREAD_TYPE_NULL; + + for (int i = 0; i < Status_Type_Count; i++) + { + m_DetStatusList[i] = Thread_Status_IDE; + } + m_nTestNum = 9999999; + m_pALLImgCheckAnalysisy = NULL; + + m_pextractImg = NULL; +} + +deal::~deal() +{ +} + +int deal::start() +{ + + std::string strdate = CheckUtil::getCurrentDate(); + printf("===== %s\n", strdate.c_str()); + int re = Init(); + // getchar(); + // 配置系统运行的cup核数。 + + if (re != 0) + { + return 1; + } + // 解析图片,并保存 + if (Process_Run_SaveImg == runConfig.run_Type) + { + Testsaveimg(); + return 1; + } + else if (runConfig.run_Type == Process_Run_ReJson) + { + + ReJson_ALL(); + return 0; + } + else + { + DetImg(); + } + + return 0; +} + +int deal::Init() +{ + InitCPUIDX(); + // 读取系统配置文件 + int re = ReadSystemConfig(FILE_SYSTEM_RUN_CONFIG); + if (re == false) + { + printf("ReadSystemConfig error\n"); + return 1; + } + // 加载 检测 的通道 图片名称 + std::string strchannlePath = m_system_param.config_Root_Path + "surface_list.json"; + m_image_ReadChannel.ReadJsonConfig(strchannlePath); + // getchar(); + + // 如果是 cell aoi 需要 加载初始化 图片解密 库 + InitExtractImg(); + + if (Process_Run_SaveImg == runConfig.run_Type) + { + return 0; + } + + // getchar(); + // 初始化参数模块 + InitConfig(); + + printf("\n\n\n\n\n\n\n\n\n\n\n**********************************************************LoadCheckImgConfig\n"); + // 载入参数 + re = LoadCheckImgConfig(); + if (re != 0) + { + printf("read config error\n"); + return 2; + } + printf("\n\n**********************************************************InitCheckAnalysisy\n"); + + // 初始化检测库 + InitCheckAnalysisy(); + printf("\n\n\n\n\n\n\n\n\n\n\n**********************************************************Check\n"); + return 0; +} + +int deal::LoadCheckImgConfig() +{ + + int re = LoadAnalysisConfig(); + if (re != 0) + { + return re; + } + + // re = LoadCheckConfig(); + // if (re != 0) + // { + // return re; + // } + + return 0; +} + +int deal::InitCheckAnalysisy() +{ + int re = 0; + int m_nMAX_GPU_NUM = MAX_GPU_NUM; + if (m_nMAX_GPU_NUM <= 0) + { + printf(">>>>error GPU error %d \n", m_nMAX_GPU_NUM); + return 2; + } + int startidx = m_CPUInfo[THREAD_CPU_CheckSo].startIdx; + int cpunum = m_CPUInfo[THREAD_CPU_CheckSo].num; + m_RunConfig.nCpu_start_Idx = startidx; + m_RunConfig.nCpu_num = cpunum; + m_pALLImgCheckAnalysisy = ALLImgCheckBase::GetInstance(); + re = m_pALLImgCheckAnalysisy->UpdateConfig((void *)&m_RunConfig, CHECK_CONFIG_Run); + re = m_pALLImgCheckAnalysisy->UpdateConfig((void *)m_pConfigManager, CHECK_CONFIG_Module); + + VERSION_INFO tm; + tm.InterfaceVersion = ALL_INTERFACE_VERSION; + tm.ConfigVersion = CONFIGBASE_VERSION; + tm.ResultVersion = RESULT_VERSION; + re = m_pALLImgCheckAnalysisy->RunStart(&tm); + if (re != 0) + { + printf("RunStart Fail %d\n", re); + return re; + } + + printf(">>>> ImgCheckThread Start Succ \n"); + return 0; +} + +int deal::InitConfig() +{ + m_pConfigManager = ConfigManagerBase::GetInstance(); + + return 0; +} + +int deal::InitExtractImg() +{ + m_pextractImg = ExtractBase::GetInstance(); + // cv::Mat outimg; + // m_pextractImg->ReadCELLImg("/mnt/4116e2a5-46a0-4c3e-a6e2-ed30d3ed7012/downloads/TestSets02/Cell AOI/20250627/研磨划伤和圈印/27圈印/6L7F52D001A2AEA/CA_20250508074237.ytimage",outimg); + return 0; +} + +int deal::InitSaveImgPath() +{ + return 0; +} + +int deal::LoadCheckConfig() +{ + + return 0; +} +int deal::LoadAnalysisConfig() +{ + if (!m_pConfigManager) + { + return 1; + } + std::string folder = m_system_param.config_Root_Path; + + int re = m_pConfigManager->LoadAnalysisConfig(folder); + + // for (const auto &pair : m_pConfigManager->Config_instances_) + // { + // std::cout << "cam: " << pair.first << std::endl; + // } + // getchar(); + return re; +} +int deal::StartThread(THREAD_RUN_TYPE type) +{ + m_bExit = false; + // 只读图线程 + if (type == THREAD_RUN_ALL) + { + + // 开启检测线程 + ptr_DealImgthread = std::make_shared(&deal::DealImg, this); + // 结果处理线程 + // ptr_Resultthread = std::make_shared(&deal::ResultThread, this); + + for (int i = 0; i < Save_IMG_THREAD_NUM; ++i) + { + // 创建线程,并使用 std::make_shared 创建 shared_ptr + std::shared_ptr threadPtr = std::make_shared(&deal::ResultThread, this, i); + // 将 shared_ptr 添加到 vector 中 + ptr_ResultthreadList.push_back(threadPtr); + } + + // 结果拷贝线程 + ptr_GetResultthread = std::make_shared(&deal::GetResultThread, this); + } + + for (int i = 0; i < READ_IMG_THREAD_NUM; ++i) + { + // 创建线程,并使用 std::make_shared 创建 shared_ptr + std::shared_ptr threadPtr = std::make_shared(&deal::ReadImgThread, this, i); + // 将 shared_ptr 添加到 vector 中 + threadArray.push_back(threadPtr); + } + + return 0; +} + +int deal::StopThread() +{ + return 0; +} +int deal::preCheck() +{ + string cur_time = CheckUtil::getCurTimeHMS(); + printf("[%s]>>> preCheck start \n", cur_time.c_str()); + + std::string strRoot = "../data/img/t1"; + std::string strProductID = ""; + std::string strRoot2 = "../data/img/t1"; + { + + READ_IMG_INFO read; + readTestImg(read); + strRoot = read.strpath; + strProductID = read.strproduct; + strRoot2 = read.strpath_2; + printf("strSearchImg strRoot %s\n", strRoot.c_str()); + + std::ifstream file123(strRoot); + bool bhave = file123.good(); + if (!bhave) + { + printf("read img path error %d %s\n", bhave, strRoot.c_str()); + return 1; + } + } + + // 获取图片路径 + + std::string strSearchImg = strRoot; + + Read_Image dfe; + int re = 0; + dfe.pimage_ReadChannel = &m_image_ReadChannel; + if (strRoot2 != "") + { + re = dfe.Read_Image_List(strSearchImg, strRoot2, strProductID); + } + else + { + re = dfe.Read_Image_List(strSearchImg, strProductID); + } + + if (re != 0) + { + + return re; + } + if (dfe.m_product_Camera_List.size() <= 0) + { + printf("error m_product_Camera_List.size() %d \n", dfe.m_product_Camera_List.size()); + return -1; + } + int idx = 0; + for (int i = 0; i < dfe.m_product_Camera_List.size(); i++) + { + if (dfe.m_product_Camera_List[i]->strProductID == strProductID) + { + idx = i; + break; + } + } + std::shared_ptr product = dfe.m_product_Camera_List[idx]; + + int AllImgNum = product->getImgNum(); + printf("product %s img num %d \n", product->strProductID.c_str(), AllImgNum); + long t1 = getcurTime(); + // 读图现场都开启 + setReadThreadStart(); + // 遍历所有图片 开始读图处理 + AllImgNum = 0; + for (const auto pcam : product->camera_list) + { + std::shared_ptr tem = std::make_shared(); + tem->strCamID = pcam->strCamName; + for (const auto pimage : pcam->image_list) + { + tem->strchannelName = pimage->strchannelName; + tem->strName = pimage->strName; + tem->strProductID = pimage->strProductID; + + if (tem->strPath == "") + { + tem->strPath = pimage->strPath; + } + else + { + tem->strPath_B = pimage->strPath; + } + } + InsertReadImgInfo(tem); + AllImgNum++; + // break; + } + // AllImgNum = 1; + { + IN_IMG_Status_ temstatus = IN_IMG_Status_Start; + std::shared_ptr tempDetImageInfo = nullptr; + + int pushImgNum = 0; + long det_time_start = getcurTime(); + std::string strImgSN = strProductID; + int GetImgNum = 0; + while (true) + { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); // + int ThreadIdx = GetReadImgCompleteThreadIdx(); + if (ThreadIdx < 0) + { + continue; + } + std::shared_ptr pDetImageInfo = nullptr; + pDetImageInfo = m_ReadImgThread_Result[ThreadIdx]; + + // 开始送到检测进行处理 + if (pDetImageInfo != nullptr) + { + // printf(">>> %s----start \n", pDetImageInfo->strName.c_str()); + tempDetImageInfo = pDetImageInfo; + int re = SendImgToCheck(pDetImageInfo, temstatus); + if (re != 0) + { + continue; + } + } + SetStatus_List(ThreadIdx, Thread_Status_READY); + GetImgNum++; + + if (IN_IMG_Status_Start == temstatus) + { + temstatus = IN_IMG_Status_Other; + } + + // 图是否都读取完了。 + bool bReadCompleted = false; + + if (GetImgNum >= AllImgNum) + { + bReadCompleted = true; + } + + // 退出 + if (bReadCompleted) + { + SendImgToCheck(tempDetImageInfo, IN_IMG_Status_End); + break; + } + } + string cur_time = CheckUtil::getCurTimeHMS(); + printf("[%s]>>> preCheck push img end \n", cur_time.c_str()); + int getresultNum = 0; + while (true) + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟消费过程 + // 处理结果 + + std::shared_ptr checkResult; + int re = m_pALLImgCheckAnalysisy->GetCheckReuslt(checkResult); + + saveImg("/home/aidlux/BOE/CELL_AOI/testresult/", checkResult); + getresultNum++; + if (getresultNum == pushImgNum) + { + + break; + } + } + } + printf(">>> ALL preCheck complete \n"); + return 0; +} + +int deal::Testsaveimg() +{ + printf(">>> preCheck start \n"); + + std::string strRoot = "../data/img/t1"; + std::string strProductID = ""; + { + + READ_IMG_INFO read; + readTestImg(read); + strRoot = read.strpath; + strProductID = read.strproduct; + printf("strSearchImg strRoot %s\n", strRoot.c_str()); + + std::ifstream file123(strRoot); + bool bhave = file123.good(); + if (!bhave) + { + printf("read img path error %d %s\n", bhave, strRoot.c_str()); + return 1; + } + } + // 获取图片路径 + std::string strSearchImg = strRoot; + + Read_Image dfe; + dfe.pimage_ReadChannel = &m_image_ReadChannel; + int re = dfe.Read_Image_List(strSearchImg, strProductID); + if (re != 0) + { + return re; + } + if (dfe.m_product_Camera_List.size() <= 0) + { + return -1; + } + int idx = 0; + for (int i = 0; i < dfe.m_product_Camera_List.size(); i++) + { + if (dfe.m_product_Camera_List[i]->strProductID == strProductID) + { + idx = i; + break; + } + } + std::shared_ptr product = dfe.m_product_Camera_List[idx]; + + int AllImgNum = product->getImgNum(); + printf("product %s img num %d \n", product->strProductID.c_str(), AllImgNum); + + long t1 = getcurTime(); + // 读图现场都开启 + + for (const auto pcam : product->camera_list) + { + + for (const auto pimage : pcam->image_list) + { + + cv::Mat img; + long t1 = CheckUtil::getcurTime(); + re = m_pextractImg->ReadCELLImg(pimage->strPath, img, runConfig.bdecode); + long t2 = CheckUtil::getcurTime(); + printf("read re = %d img time %ld ms \n", re, t2 - t1); + + if (!img.empty()) + { + cv::imwrite(pimage->strName + ".jpg", img); + } + else + { + printf("img.empty() \n"); + } + + // getchar(); + } + } + + return 0; +} + +std::string deal::readTestImg() +{ + std::string strRoot = "../data/img/TestImg.json"; + printf("Reading Img config %s\n", strRoot.c_str()); + Json::CharReaderBuilder builder; + builder["collectComments"] = true; + Json::Value root; + std::string err; + std::ifstream ifs(strRoot); + if (!ifs.is_open()) + { + printf("error:file is open\n"); + return ""; + } + if (!Json::parseFromStream(builder, ifs, &root, &err)) + { + printf("error:parseFromStream\n"); + return ""; + } + std::string imgpath = ""; + imgpath = root["TestImg_Path"].asString(); + + return imgpath; +} + +int deal::readTestImg(READ_IMG_INFO &read) +{ + std::string strRoot = "../data/img/TestImg.json"; + printf("Reading Img config %s\n", strRoot.c_str()); + Json::CharReaderBuilder builder; + builder["collectComments"] = true; + Json::Value root; + std::string err; + std::ifstream ifs(strRoot); + if (!ifs.is_open()) + { + printf("error:file is open\n"); + return 1; + } + if (!Json::parseFromStream(builder, ifs, &root, &err)) + { + printf("error:parseFromStream\n"); + return 1; + } + std::string imgpath = ""; + read.strpath = root["TestImg_Path"].asString(); + read.strproduct = root["ProductID"].asString(); + if (root["TestImg_2_Path"]) + { + read.strpath_2 = root["TestImg_2_Path"].asString(); + } + else + { + read.strpath_2 = ""; + } + + return 0; +} + +int deal::repeatCheck() +{ + + return 0; +} + +int deal::saveImg(std::string strpath, std::shared_ptr result) +{ + std::string strroot = strpath; + std::string strroot_qx = strpath; + if (result->in_shareImage->imgstr != "") + { + strroot += result->in_shareImage->imgstr; + strroot += "/"; + strroot_qx += result->in_shareImage->imgstr; + strroot_qx += "/"; + } + + if (strpath != "") + { + + strroot_qx += "qx/"; + + if (result->nProductResult != 0) + { + strroot += "NG/"; + } + else + { + strroot += "OK/"; + } + + if (result->in_shareImage->strImgProductID != "") + { + strroot += result->in_shareImage->strImgProductID + "/"; + } + + if (result->nresult != 0) + { + strroot += "NG/"; + } + else + { + if (result->nYS_result != 0) + { + strroot += "OK/YS/"; + } + else + { + strroot += "OK/OK/"; + } + } + } + printf("result->nresult %d %d \n", result->nresult, result->nYS_result); + printf("%s\n", strroot.c_str()); + _sysmkdirs_1(strroot); + std::string str_saveName = ""; + // getchar(); + if (result->in_shareImage->strImgProductID != "") + { + strroot += result->in_shareImage->strImgProductID; + str_saveName += result->in_shareImage->strImgProductID; + } + + if (result->in_shareImage->strImgName != "") + { + strroot += "_" + result->in_shareImage->strImgName; + str_saveName += "_" + result->in_shareImage->strImgName; + } + { + std::string strcam = std::to_string(result->in_shareImage->camera_ID); + strroot += "_" + strcam; + str_saveName += "_" + strcam; + } + + writeLog(strroot, result->det_LogList); + WriteJsonString(strroot, result->strResultJson); + // printf("%s \n", strroot.c_str()); + std::string str = strroot + "_RE_Resultimg.png"; + if (!result->resultimg.empty()) + { + cv::imwrite(str, result->resultimg); + } + std::string str123 = strroot + "_RE_CutImg.png"; + if (!result->cutSrcimg.empty()) + { + cv::imwrite(str123, result->cutSrcimg); + } + std::string str123r = strroot + "_RE_CutDrawImg.png"; + if (!result->SrcResultImg.empty()) + { + cv::imwrite(str123r, result->SrcResultImg); + } + std::string strMask = strroot + "_RE_AIMask.png"; + + if (!result->resultMaskImg.empty()) + { + cv::imwrite(strMask, result->resultMaskImg); + } + std::string str_qx; + printf("result->qxImageResult.size() %ld \n", result->qxImageResult.size()); + for (int i = 0; i < result->qxImageResult.size(); i++) + { + std::string str = strroot + "_RE_" + std::to_string(i) + "_Src.png"; + + if (!result->qxImageResult.at(i).srcImg.empty()) + { + cv::imwrite(str, result->qxImageResult.at(i).srcImg); + } + + str_qx = strroot_qx + result->qxImageResult.at(i).strTypeName + "/"; + printf("-1-- %s\n", str_qx.c_str()); + _sysmkdirs_1(str_qx); + str_qx += str_saveName + "_RE_" + std::to_string(i) + "_Src.png"; + // printf("-2-- %s\n", str_qx.c_str()); + + if (!result->qxImageResult.at(i).srcImg.empty()) + { + cv::imwrite(str_qx, result->qxImageResult.at(i).srcImg); + } + str_qx = strroot_qx + result->qxImageResult.at(i).strTypeName + "/"; + str_qx += str_saveName + "_RE_" + std::to_string(i) + "_Small.png"; + + if (!result->qxImageResult.at(i).resizeImg.empty()) + { + cv::imwrite(str_qx, result->qxImageResult.at(i).resizeImg); + } + + { + str_qx = strroot_qx + result->qxImageResult.at(i).strTypeName + "/"; + str_qx += str_saveName + "_RE_" + std::to_string(i) + "_AI_In.png"; + if (!result->qxImageResult.at(i).AI_in_Img.empty()) + { + cv::imwrite(str_qx, result->qxImageResult.at(i).AI_in_Img); + } + + str_qx = strroot_qx + result->qxImageResult.at(i).strTypeName + "/"; + str_qx += str_saveName + "_RE_" + std::to_string(i) + "_AI_In_mask.png"; + if (!result->qxImageResult.at(i).AI_out_img.empty()) + { + cv::imwrite(str_qx, result->qxImageResult.at(i).AI_out_img); + } + } + + // printf("-1111-- %s\n", str_qx.c_str()); + std::string str1 = strroot + "_RE_" + std::to_string(i) + "_Small.png"; + + if (!result->qxImageResult.at(i).resizeImg.empty()) + { + cv::imwrite(str1, result->qxImageResult.at(i).resizeImg); + } + } + printf("result->YS_ImageResult.size() %ld\n", result->YS_ImageResult.size()); + for (int i = 0; i < result->YS_ImageResult.size(); i++) + { + std::string str = strroot + "_RE_" + std::to_string(i) + "_YS_Src.png"; + if (result->YS_ImageResult.at(i).srcImg.empty()) + { + printf("resqwwwwwwwwwwwwwwwult->YS_ImageResult.size() %ld \n", result->YS_ImageResult.size()); + } + + if (!result->YS_ImageResult.at(i).srcImg.empty()) + { + cv::imwrite(str, result->YS_ImageResult.at(i).srcImg); + } + str_qx = strroot_qx + result->YS_ImageResult.at(i).strTypeName + "/"; + // printf("-3-- %s\n", str_qx.c_str()); + _sysmkdirs_1(str_qx); + str_qx += str_saveName + "_RE_" + std::to_string(i) + "_YS_Src.png"; + // printf("-4-- %s\n", str_qx.c_str()); + + if (!result->YS_ImageResult.at(i).srcImg.empty()) + { + cv::imwrite(str_qx, result->YS_ImageResult.at(i).srcImg); + } + str_qx = strroot_qx + result->YS_ImageResult.at(i).strTypeName + "/"; + str_qx += str_saveName + "_RE_" + std::to_string(i) + "_YS_Small.png"; + + if (!result->YS_ImageResult.at(i).resizeImg.empty()) + { + cv::imwrite(str_qx, result->YS_ImageResult.at(i).resizeImg); + } + { + str_qx = strroot_qx + result->YS_ImageResult.at(i).strTypeName + "/"; + str_qx += str_saveName + "_RE_" + std::to_string(i) + "_YS_AI_In.png"; + if (!result->YS_ImageResult.at(i).AI_in_Img.empty()) + { + cv::imwrite(str_qx, result->YS_ImageResult.at(i).AI_in_Img); + } + + str_qx = strroot_qx + result->YS_ImageResult.at(i).strTypeName + "/"; + str_qx += str_saveName + "_RE_" + std::to_string(i) + "_YS_AI_In_mask.png"; + if (!result->YS_ImageResult.at(i).AI_out_img.empty()) + { + cv::imwrite(str_qx, result->YS_ImageResult.at(i).AI_out_img); + } + } + // printf("-1111-- %s\n", str_qx.c_str()); + std::string str1 = strroot + "_RE_" + std::to_string(i) + "_YS_Small.png"; + + if (!result->YS_ImageResult.at(i).resizeImg.empty()) + { + cv::imwrite(str1, result->YS_ImageResult.at(i).resizeImg); + } + } + return 0; +} + +int deal::writeLog(std::string strSavePath, std::vector logList) +{ + std::string str = strSavePath + ".txt"; + // 打开文件 + std::ofstream outFile(str); + + // 检查文件是否成功打开 + if (!outFile) + { + std::cerr << "Failed to open file." << std::endl; + return 1; + } + + // 将vector中的内容写入文件 + for (const auto &str : logList) + { + // printf("%s \n",str.c_str()); + outFile << str << std::endl; + } + + // 关闭文件 + outFile.close(); + + return 0; +} + +int deal::WriteJsonString(std::string strSavePath, std::string strjson) +{ + + std::string str = strSavePath + ".json"; + // 打开文件 + std::ofstream outFile(str); + + // 检查文件是否成功打开 + if (!outFile) + { + std::cerr << "Failed to open file." << std::endl; + return 1; + } + + // 将vector中的内容写入文件 + outFile << strjson << std::endl; + + // 关闭文件 + outFile.close(); + return 0; +} + +void deal::ResultThread(int id) +{ + std::vector vi; + int startidx = m_CPUInfo[THREAD_CPU_Main_saveImg].startIdx; + int cpunum = m_CPUInfo[THREAD_CPU_Main_saveImg].num; + // for (int i = 0; i < cpunum; i++) + // { + // vi.push_back(startidx + i); + // } + vi.push_back(startidx + id); + auto nRet = set_cpu_id(vi); + printf("THREAD_CPU_Main_saveImg %d bind cpu ret %d startidx %d num %d\n", id, nRet, startidx + id, 1); + + int re = 0; + cv::Mat detImg; + int kkkkk = 0; + static int saveidx = 0; + while (!m_bExit) + { + std::shared_ptr dealResult; + mutex_Result_list.lock(); + if (m_Result_list.size() > 0) + { + dealResult = m_Result_list.front(); + m_Result_list.pop(); + if (m_Result_list.size() > 10) + { + printf("Result_list size %ld \n", m_Result_list.size()); + } + + mutex_Result_list.unlock(); + } + else + { + mutex_Result_list.unlock(); + usleep(10000); + continue; + } + + { + updataResltInfo(dealResult); + } + + { + if (true) + { + // 存图 + // std::string savepath = "/home/aidlux/BOE/Detsave/" + runConfig.filePath + "/"; + // saveImg(savepath, dealResult); + saveImg("/home/aidlux/BOE/CELL_AOI/Detsave/", dealResult); + } + + { + // 存 检测统计 日志 + mutex_DetResult_.lock(); + m_DetResult.print(false); + std::string strlog = "/home/aidlux/BOE/CELL_AOI/ResultImg/"; + if (m_strCurDate != "") + { + strlog += m_strCurDate; + strlog += "/result"; + } + else + { + strlog += "/result"; + } + + writeLog(strlog, m_DetResult.strlist); + mutex_DetResult_.unlock(); + } + } + + usleep(5 * 1000); + } +} +int deal::set_cpu_id(const std::vector &cpu_set_vec) +{ + // for cpu affinity + int nRet = 0; +#ifdef __linux + cpu_set_t _cur_cpu_set; + CPU_ZERO(&_cur_cpu_set); + for (auto _id : cpu_set_vec) + { + CPU_SET(_id, &_cur_cpu_set); + } + if (0 > pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &_cur_cpu_set)) + { + perror("set cpu affinity failed: "); + printf("Warning: set cpu affinity failed ... ...\n"); + nRet = -1; + } +#endif //__linux + return nRet; +} + +void deal::GetDealResultToQueu() +{ + + // 处理结果 + + std::shared_ptr checkResult; + if (!m_pALLImgCheckAnalysisy) + { + return; + } + + int re = m_pALLImgCheckAnalysisy->GetCheckReuslt(checkResult); + + if (re == 0) + { + mutex_Result_list.lock(); + m_Result_list.push(checkResult); + mutex_Result_list.unlock(); + } + else + { + printf("Check error >>>>>>>>>>>>>>>>> \n"); + } + + return; +} +bool deal::ReadSystemConfig(const std::string &strPath) +{ + + printf("Reading system config %s\n", strPath.c_str()); + Json::CharReaderBuilder builder; + builder["collectComments"] = true; + Json::Value root; + std::string err; + std::ifstream ifs(strPath); + if (!ifs.is_open()) + { + printf("error:file is open\n"); + return false; + } + if (!Json::parseFromStream(builder, ifs, &root, &err)) + { + printf("error:parseFromStream\n"); + return false; + } + m_system_param.Use_CPU_StartIdx = root["Use_CPU_StartIdx"].asInt(); + // path + m_system_param.Analysis_Config_path = root["Analysis_Config_path"].asString(); + m_system_param.Analysis_Config_path_Cam2 = root["Analysis_Config_path_Cam2"].asString(); + m_system_param.config_Root_Path = root["Config_Root_Path"].asString(); + m_system_param.Check_Config_path = root["Check_Config_path"].asString(); + + m_system_param.preCheckImg_Path = root["preCheckImg_Path"].asString(); + m_system_param.preCHeck_YX = root["preCHeck_YX"].asInt(); + m_system_param.preCHeck_defect = root["preCHeck_defect"].asInt(); + m_nCurUseCPUIDX = m_system_param.Use_CPU_StartIdx; + + return m_system_param.valid(); +} +int deal::GetJcImageInfo(std::string strpath, std::vector &jcImageInfoList) +{ + LoadOfflineCheckImg(strpath); + jcImageInfoList.erase(jcImageInfoList.begin(), jcImageInfoList.end()); + + // 遍历每一套图片 + for (int idx = 0; idx < m_OffLineCheckImgNameList.size(); idx++) + { + std::string path = m_OffLineCheckImgNameList.at(idx); + JC_IMAGE_INFO_ tem; + int re = GetImgInfo_POL_ET(path, &tem); + } + // getchar(); + return 0; +} +int deal::GetDetImageInfo(std::string strProductID, std::string strSearchImg, std::vector &jcImageInfoList) +{ + // 1、获取图片路径 + std::vector img_paths; + std::string strs1 = strSearchImg + "/*.ytimage"; + if(!runConfig.bdecode) + { + strs1 = strSearchImg + "/*.jpg"; + } + cv::glob(strs1, img_paths, true); + // printf("%ld \n", img_paths.size()); + + jcImageInfoList.erase(jcImageInfoList.begin(), jcImageInfoList.end()); + + // 遍历每一套图片 + for (int idx = 0; idx < img_paths.size(); idx++) + { + // printf("---- %d / %d %s----\n", idx, m_OffLineCheckImgNameList.size(), m_OffLineCheckImgNameList.at(idx).c_str()); + + std::string path = img_paths.at(idx); + + JC_IMAGE_INFO_ tem; + int re = 0; + { + re = GetImgInfo_POL_ET(path, &tem); + if (re != 0) + { + continue; + } + } + tem.strProductID = strProductID; + + jcImageInfoList.push_back(tem); + } + + return 0; +} +int deal::GetImgInfo_POL_ET(std::string strImgPath, JC_IMAGE_INFO_ *pImageInfo) +{ + + if (pImageInfo == NULL) + { + return 1; + } + string strName = ""; + size_t lastUnderscore; + strName = ExtractFileNameWithoutExtension(strImgPath); + printf("strName %s \n", strName.c_str()); + + std::string strImageChannel; + + // 使用 find 检查是否包含 "CA" 或 "TA" + if (strName.find("CA") != std::string::npos || strName.find("CF") != std::string::npos) + { + strImageChannel = "CA"; + } + else if (strName.find("TA") != std::string::npos || strName.find("TFT") != std::string::npos) + { + strImageChannel = "TA"; + } + else + { + return 1; + } + printf("strImageChannel %s\n", strImageChannel.c_str()); + pImageInfo->strchannelName = strImageChannel; + pImageInfo->strName = strName; + pImageInfo->strPath = strImgPath; + pImageInfo->strCamID = strImageChannel; + printf("strImgPath %s strName %s strChannel %s\n", strImgPath.c_str(), strName.c_str(), strImageChannel.c_str()); + + return 0; +} +int deal::GetImgInfo_POL_ET_PNG(std::string strImgPath, JC_IMAGE_INFO_ *pImageInfo) +{ + + if (pImageInfo == NULL) + { + return 1; + } + + string strImageChannel = ExtractFileNameWithoutExtension(strImgPath); + printf("strImageChannel %s\n", strImageChannel.c_str()); + std::string strChannle = m_image_ReadChannel.strDetName(strImageChannel); + if (strChannle == "") + { + return 1; + } + + pImageInfo->strchannelName = strChannle; + pImageInfo->strName = strChannle; + pImageInfo->strPath = strImgPath; + pImageInfo->strCamID = "0"; + // printf("strImgPath %s strChannel %s\n", strImgPath.c_str(), strChannle.c_str()); + + // 使用 find 函数检查是否包含 "_左" + if (strImgPath.find("_工位右") != std::string::npos) + { + pImageInfo->strCamID = "1"; + ; + } + return 0; +} +int deal::ReadTestImgaData() +{ + std::string strPath = "../data/testImg.json"; + printf("ReadTestImgaData config %s\n", strPath.c_str()); + Json::CharReaderBuilder builder; + builder["collectComments"] = true; + Json::Value root; + std::string err; + std::ifstream ifs(strPath); + if (!ifs.is_open()) + { + printf("error:file is open\n"); + return false; + } + if (!Json::parseFromStream(builder, ifs, &root, &err)) + { + printf("error:parseFromStream\n"); + return false; + } + m_TestJC_ImageDate.erase(m_TestJC_ImageDate.begin(), m_TestJC_ImageDate.end()); + { + auto value = root["img_date"]; + if (value.isObject()) + { + auto arr = value["date"]; + std::cout << arr << std::endl; + if (arr.isArray()) + { + + // 遍历数组中的每个元素 + for (int i = 0; i < arr.size(); i++) + { + + // 读取对象中的属性值 + std::string strdata = arr[i].asString(); + m_TestJC_ImageDate.push_back(strdata); + + // 输出属性值 + std::cout << "date: " << strdata << std::endl; + } + } + } + } + // getchar(); + return 0; +} +int deal::InitDetData() +{ + m_read_ImgNum = 0; + return 0; +} +int deal::InsertDetResult(ReadImgInfo tem) +{ + std::lock_guard lock(mtx_List[Mutex_Type_DetResult]); + m_DetResultList.push_back(tem); + + return 0; +} +int deal::GetUpMaskImg(cv::Mat inImg, cv::Rect roi, cv::Mat &maskimg) +{ + // 定义滑动窗口的大小和步长 + int windowWidth = 128; + int windowHeight = 128; + int stepX = 110; // 横向步长 + int stepY = 110; // 纵向步长 + + maskimg = cv::Mat(roi.height, roi.width, CV_8U, cv::Scalar(0)); + int sx = roi.x; + int ex = roi.x + roi.width; + int sy = roi.y; + int ey = roi.y + roi.height; + + cv::Rect detroi; + detroi.width = windowWidth; + detroi.height = windowHeight; + cv::Rect maskroi; + maskroi.width = windowWidth; + maskroi.height = windowHeight; + cv::Mat temmask; + // 遍历图像,使用滑动窗口 + for (int y = sy; y <= ey; y += stepY) + { + detroi.y = y; + if (detroi.y + windowHeight > ey) + { + detroi.y = ey - windowHeight; + } + maskroi.y = detroi.y - sy; + + for (int x = sx; x <= ex; x += stepX) + { + detroi.x = x; + if (detroi.x + windowWidth > ex) + { + detroi.x = ex - windowWidth; + } + maskroi.x = detroi.x - sx; + int thresholdValue = 30; // 初始阈值,OTSU将自动计算 + int maxVal = 255; // 最大值 + double otsuThreshold; + + cv::Scalar mean, stddev; + cv::meanStdDev(inImg(detroi), mean, stddev); + + int varianceImg; + varianceImg = mean[0] + 1 * mean[0]; + if (mean[0] > 100) + { + continue; + } + + // 使用 OTSU 阈值处理 + otsuThreshold = cv::threshold(inImg(detroi), temmask, thresholdValue, maxVal, cv::THRESH_BINARY | cv::THRESH_OTSU); + thresholdValue = otsuThreshold; + + if (thresholdValue < 30) + { + thresholdValue = 30; + } + if (thresholdValue < varianceImg) + { + thresholdValue = varianceImg; + } + + if (thresholdValue > 100) + { + continue; + } + // std::cout << "varianceImg value is: " << varianceImg << std::endl; + // std::cout << "OTSU threshold value is: " << otsuThreshold << std::endl; + // std::cout << "stddev[0] value is: " << stddev[0] << std::endl; + otsuThreshold = cv::threshold(inImg(detroi), maskimg(maskroi), thresholdValue, maxVal, cv::THRESH_BINARY); + // cv::threshold(inImg(detroi), maskimg(maskroi), thresholdValue, maxVal, cv::THRESH_BINARY + cv::THRESH_OTSU); + // 提取当前窗口 + + // cv::rectangle(inImg, detroi, cv::Scalar(255, 0, 0)); + } + } + // cv::imwrite("inImg1123.png", inImg); + // cv::imwrite("maskimg.png", maskimg); + // getchar(); + return 0; +} +int deal::SendImgToCheck(std::shared_ptr pDetImageInfo, IN_IMG_Status_ status) +{ + + if (pDetImageInfo == nullptr) + { + return -1; + } + if (status == IN_IMG_Status_End) + { + std::shared_ptr tem = std::make_shared(); + tem->strImgProductID = pDetImageInfo->strProductID; + tem->Status = -1; + if (m_pALLImgCheckAnalysisy) + { + m_pALLImgCheckAnalysisy->SetDataRun_SharePtr(tem); + } + return 0; + } + + std::shared_ptr tem = std::make_shared(); + + tem->strChannel = pDetImageInfo->strchannelName; + string cur_time = CheckUtil::getCurTimeHMS(); + printf("[%s]========SendImgToCheck============ %s \n", cur_time.c_str(), tem->strChannel.c_str()); + + // cv::imwrite(tem->strChannel+".png",pDetImageInfo->img); + tem->nImgBigIdx = 0; + tem->strImgName = pDetImageInfo->strName; + tem->strImgProductID = pDetImageInfo->strProductID; + tem->imgstr = m_strCurDate; + tem->strCameraName = pDetImageInfo->strCamID; + tem->camera_ID = 0; + if (m_nSaveDetprocessImg == 1) + { + tem->otherValue = 9; + } + if (pDetImageInfo->img_B.empty()) + { + tem->bCam_AB = false; + } + else + { + tem->bCam_AB = true; + tem->img_B = pDetImageInfo->img_B; + } + + tem->getImgTimeMs = getcurTime(); + tem->readImg_start = pDetImageInfo->readImg_start; + tem->readImg_end = pDetImageInfo->readImg_end; + tem->Status = status; + tem->Det_Mode = DET_MODE_Det; + if ( runConfig.det_Type == RUNTYPE_RUN_Merge_Img) + { + tem->Det_Mode = DET_MODE_MergeImg; + } + + tem->img = pDetImageInfo->img; + if (m_nSaveDetprocessImg == 1) + { + tem->bsaveProcessImg = true; + } + if (runConfig.bSaveProcessImg) + { + tem->bsaveProcessImg = true; + } + + + int re = 0; + if (m_pALLImgCheckAnalysisy) + { + re = m_pALLImgCheckAnalysisy->SetDataRun_SharePtr(tem); + } + + return re; +} +int deal::ReJson() +{ + return 0; +} +int deal::ReJson_ALL() +{ + printf(">>> ReJson ALL start \n"); + + // 1、获取所有的json + std::vector img_paths; + cv::glob(runConfig.filePath + "/*.json", img_paths, true); + if (img_paths.size() <= 0) + { + printf("json file is NULL \n"); + return 1; + /* code */ + } + // 用map存储每个id对应的vector + std::unordered_map> ProductJsonList; + // 遍历路径并按照ID分组 + for (const auto &path : img_paths) + { + // 获取路径中的 ID 部分(即文件夹名部分) + size_t start_pos = path.find_last_of("/") + 1; + size_t end_pos = path.find("_", start_pos); + std::string id = path.substr(start_pos, end_pos - start_pos); + // printf("id %s\n",id.c_str()); + // 将文件路径加入对应 ID 的vector中 + ProductJsonList[id].push_back(path); + } + for (const auto &product : ProductJsonList) + { + std::cout << product.first << " => " << product.second.size() << std::endl; + std::vector jsonList; + std::string strProductName = product.first; + for (const auto &str : product.second) + { + { + // 2、获取第一个 名称 + std::string strPath = str; + size_t lastSlashPos = strPath.find_last_of('/'); + // 提取文件名(从最后一个斜杠之后的部分) + std::string filename = strPath.substr(lastSlashPos + 1); + // 查找文件名中的第一个下划线位置 + size_t firstUnderscorePos = filename.find('_'); + // 提取文件名中的名称部分(下划线之前的字符串) + std::string strProduct = filename.substr(0, firstUnderscorePos); + // printf("strProduct %s \n", strProduct.c_str()); + if (strProduct == strProductName) + { + Json_Det_Path tem; + tem.strPath_Json = str; + tem.strPath_CutImg = str; + size_t pos = tem.strPath_CutImg.rfind(".json"); + + if (pos != std::string::npos) + { + // 替换 ".json" 为 "_RE_CutImg.png" + tem.strPath_CutImg.replace(pos, 5, "_RE_CutImg.png"); + } + std::cout << " Path: " << tem.strPath_Json << std::endl; + std::cout << " Path: " << tem.strPath_CutImg << std::endl; + jsonList.push_back(tem); + } + } + } + + ReJson_product(jsonList, strProductName); + } + + // 获取要检测的 json 图片 list + + printf(">>>>>>>>>>>>>>>>>>>> rejson ALL is Complete \n"); + return 0; +} +int deal::DetImg() +{ + // 单张检测 + if (runConfig.det_Type == RUNTYPE_RUN_Pre || runConfig.det_Type == RUNTYPE_RUN_Merge_Img) + { + m_nReadThread_type = READ_THREAD_TYPE_READIMG; + StartThread(THREAD_RUN_Only_ReadImg); + preCheck(); + return 0; + } + + if (runConfig.det_Type == RUNTYPE_RUN_EDGE_TEST || + runConfig.det_Type == RUNTYPE_RUN_EDGE_TEST_AI) + { + + std::string str1 = "/home/aidlux/BOE/Edge/Big/"; + _sysmkdirs_1(str1); + str1 = "/home/aidlux/BOE/Edge/Result/"; + _sysmkdirs_1(str1); + str1 = "/home/aidlux/BOE/Edge/Smasll/"; + _sysmkdirs_1(str1); + + m_nReadThread_type = READ_THREAD_TYPE_READIMG; + StartThread(THREAD_RUN_Only_ReadImg); + Det_Funtion_Test(); + return 0; + } + + m_nReadThread_type = READ_THREAD_TYPE_READIMG; + // 文件夹套图处理 + if (RUNTYPE_RUN_File == runConfig.det_Type) + { + std::string str = runConfig.filePath; + LoadProductID(str); + } + // getchar(); + m_nSystemCheckType = CHECK_TYPE_OFFLING; + StartThread(THREAD_RUN_ALL); + return 0; +} +int deal::ReJson_product(std::vector &jsonList, std::string strProductName) +{ + // 获取要检测的 json 图片 list + + int temstatus = IN_IMG_Status_Start; + int PushNum = 0; + // 开始逐一复测 + for (int i = 0; i < jsonList.size(); i++) + { + std::string strJson = jsonList.at(i).strPath_Json; + std::string strimg = jsonList.at(i).strPath_CutImg; + std::ifstream file(strJson); + + if (!file.is_open()) + { + std::cerr << "Unable to open file!" << std::endl; + return -1; + } + // 读取文件内容到 std::string + std::stringstream buffer; + buffer << file.rdbuf(); + std::string json_str = buffer.str(); // 获取 JSON 文件的内容作为字符串 + // 显示读取到的 JSON 字符串 + // std::cout << "JSON content: " << json_str << std::endl; + cv::Mat cutimg = cv::imread(strimg, 0); + int f0 = strJson.rfind('_'); + int f1 = strJson.rfind('.'); + int f2 = strJson.rfind('/'); + + std::string str1 = strJson.substr(f2 + 1, f1 - f2 - 1); + std::string str2 = strJson.substr(f0 + 1, f1 - f0 - 1); + // std::string str3 = strJson.substr(f2 + 1, strJson.size() - f2); + + std::cout << str1 << std::endl; + std::cout << str2 << std::endl; + if (str1.find("CA") != std::string::npos) + { + str2 = "CA"; + } + else if (str1.find("TA") != std::string::npos) + { + str2 = "TA"; + } + else + { + continue; + } + + std::cout << "start " << strJson << std::endl; + + std::shared_ptr result; + // 多线程 互斥 作用域 + { + + std::shared_ptr temdet = std::make_shared(); + temdet->strCameraName = str2; + temdet->strImgProductID = strProductName; + temdet->strChannel = str2; + temdet->strImgName = str1; + + std::cout << "strChannel " << temdet->strChannel << std::endl; + + temdet->Det_Mode = DET_MODE_ReJson; + temdet->img = cutimg; + temdet->resultJson = json_str; + + { + if (i == 0) + { + temdet->Status = IN_IMG_Status_Start; + } + else if (i == jsonList.size() - 1) + { + temdet->Status = IN_IMG_Status_End; + } + else + { + temdet->Status = IN_IMG_Status_Other; + } + } + + int re = m_pALLImgCheckAnalysisy->SetDataRun_SharePtr(temdet); + if (re != 0) + { + printf("reJson Error %d \n", re); + continue; + } + PushNum++; + // 结果异常 + } + } + int getresultNum = 0; + while (true) + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟消费过程 + // 处理结果 + + std::shared_ptr checkResult; + int re = m_pALLImgCheckAnalysisy->GetCheckReuslt(checkResult); + printf("********************** Get result %d -- %s \n", getresultNum, checkResult->in_shareImage->strChannel.c_str()); + saveImg("/home/aidlux/BOE/ReJsonresult/", checkResult); + getresultNum++; + if (getresultNum == PushNum) + { + break; + } + } + return 0; +} +void deal::GetResultThread() +{ + std::vector vi; + vi.push_back(18); + auto nRet = set_cpu_id(vi); + printf("bind cpu ret %d, %d\n", nRet, 18); + int re = 0; + + int nsleep1 = 2 * 1000; + + while (!m_bExit) + { + // 1、拷贝检测结果到队列 + GetDealResultToQueu(); + usleep(nsleep1); + } +} +void deal::ReadImgThread(int id) +{ + + int nsleep1 = 200 * 1000; + int readThreadIdx = id; + while (!m_bExit) + { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); // 模拟消费过程 + + // 读图模式 + if (READ_THREAD_TYPE_READIMG == m_nReadThread_type) + { + Thread_ReadImg(readThreadIdx); + } + else if (READ_THREAD_Detect == m_nReadThread_type) + { + } + } +} +void deal::testimg(cv::Mat img) +{ +} + +int deal::updataResltInfo(std::shared_ptr result) +{ + + mutex_DetResult_.lock(); + std::string productID = result->in_shareImage->strImgProductID; + std::string imgName = result->in_shareImage->strChannel; + // printf("add productID %s imgName %s %d\n", productID.c_str(), imgName.c_str(), result->nresult); + long t1 = getcurTime(); + m_DetResult.updata(productID, imgName, result->nresult, t1); + for (int i = 0; i < ERROR_TYPE_COUNT; i++) + { + if (result->defectResultList[i].nresult == 1) + { + m_DetResult.update_qx(result->defectResultList[i].keyName, result->defectResultList[i].num); + } + } + mutex_DetResult_.unlock(); + return 0; +} +// 滑动窗口二值化函数 +void deal::slidingWindowAutoThreshold(const cv::Mat &src, cv::Mat &dst, int windowSize, int step, double C) +{ + // 确保窗口大小为奇数 + // if (windowSize % 2 == 0) + // { + // windowSize++; + // } + + // 创建目标图像 + dst = cv::Mat::zeros(src.size(), CV_8UC1); + + // 获取源图像的尺寸 + int rows = src.rows; + int cols = src.cols; + int xs = 0; + int xe = windowSize; + int ys = 0; + int ye = windowSize; + for (int y = ye; y < rows;) + { + int xs = 0; + int xe = windowSize; + for (int x = xe; x < cols;) + { + + cv::Rect roi; + roi.x = xs; + roi.width = windowSize; + roi.y = ys; + roi.height = windowSize; + + cv::Mat window = src(roi); + + // 计算窗口中的平均值和标准差 + cv::Scalar mean, stdDev; + cv::meanStdDev(window, mean, stdDev); + // printf(" x %d %d y %d %d %f %f \n", xs, xe, ys, ye, mean[0], stdDev[0]); + int T = mean[0] + 20 * stdDev[0]; + cv::threshold(window, dst(roi), T, 255, cv::THRESH_BINARY); + + // cv::rectangle(src, roi, cv::Scalar(255, 0, 255)); + if (xe == cols) + { + break; + } + xs = xs + step; + xe = xs + windowSize; + if (xs < cols && xe > cols) + { + xe = cols; + xs = xe - windowSize; + } + } + if (ye == rows) + { + break; + } + ys = ys + step; + ye = ys + windowSize; + if (ys < rows && ye > rows) + { + ye = rows; + ys = ye - windowSize; + } + } + + // // 遍历图像的每个像素 + // for (int i = 0; i < rows; ++i) + // { + // for (int j = 0; j < cols; ++j) + // { + // // 计算窗口边界 + // int startRow = std::max(0, i - windowSize / 2); + // int endRow = std::min(rows - 1, i + windowSize / 2); + // int startCol = std::max(0, j - windowSize / 2); + // int endCol = std::min(cols - 1, j + windowSize / 2); + + // // 提取窗口中的图像块 + // cv::Mat window = src(cv::Range(startRow, endRow + 1), cv::Range(startCol, endCol + 1)); + + // // 计算窗口中的平均值和标准差 + // cv::Scalar mean, stdDev; + // cv::meanStdDev(window, mean, stdDev); + + // // 计算局部阈值 + // double threshold = mean[0] - C * stdDev[0]; + + // // 根据局部阈值进行二值化 + // if (src.at(i, j) >= threshold) + // { + // dst.at(i, j) = 255; + // } + // else + // { + // dst.at(i, j) = 0; + // } + // } + // } +} + +int deal::testimgUP(cv::Mat img) +{ + + cv::Mat dst; + slidingWindowAutoThreshold(img, dst, 200, 180, 10); + cv::imwrite("up_dst.png", dst); + cv::imwrite("up.png", img); + printf("1111\n"); + getchar(); + return 0; +} +int deal::test_ZF(ReadImgInfo tem, int id) +{ + std::string ressss = "**"; + for (int i = 0; i < id; i++) + { + ressss += "*******"; + } + + // printf("%s %d start redimg img idx %d ID %s ch %s tem.imglist %zu\n ", ressss.c_str(), id, tem.idx, tem.strImgSN.c_str(), tem.strChannel.c_str(), tem.imglist.size()); + long t1 = getcurTime(); + cv::Mat L255Img = cv::imread(tem.strPath, 0); + long t2 = getcurTime(); + mtx_DetImgQueue_com.lock(); + m_read_ImgNum++; + + long useTime = t2 - m_readImgStarttime; + // printf("read Img mean time %ld -- m_read_ImgNum %d use time %ld \n", useTime / m_read_ImgNum, m_read_ImgNum, useTime / 1000); + mtx_DetImgQueue_com.unlock(); + printf("---------------------ThreadID %d readimg %d / %d use time %ld %s \n", id, tem.idx, tem.sumNUm, t2 - t1, tem.strPath.c_str()); + // printf("tem.strPath %s *\n", tem.strPath.c_str()); + // printf("%s %d End redimg use time %ld \n ", ressss.c_str(), id, t2 - t1); + cv::Mat mask; + if (L255Img.empty()) + { + printf("error:No L255 Img -------------- \n"); + InsertDetResult(tem); + return 1; + } + tem.status = 1; + int re = 0; + std::shared_ptr result; + // 多线程 互斥 作用域 + // if (false) + { + std::lock_guard lock(mtx_DetImgQueue_edge); + { + + if (tem.strChannel == "L255") + { + std::shared_ptr temdet = std::make_shared(); + if (m_nSaveDetprocessImg == 1) + { + temdet->otherValue = 9; + } + temdet->strImgName = "test"; + temdet->strImgProductID = tem.strImgSN; + temdet->strChannel = tem.strChannel; + + // if (m_nReadThread_type == READ_THREAD_TYPE_EDGE) + { + temdet->Det_Mode = DET_MODE_EDGE; + if (runConfig.det_Type == RUNTYPE_RUN_EDGE_TEST_AI) + { + temdet->ninstruct = 999; + } + } + temdet->img = L255Img; + printf(">>>>>>>>>>>m_nReadThread_type %d runConfig.det_Type %d temdet->ninstruct %d >>>>>>>>> ThreadID %d start Check readimg %d / %d ID %s ch %s \n ", m_nReadThread_type, runConfig.det_Type, temdet->ninstruct, id, tem.idx, tem.sumNUm, tem.strImgSN.c_str(), tem.strChannel.c_str()); + m_pALLImgCheckAnalysisy->CheckImg(temdet, result); + // 结果异常 + if (result->nresult != 0) + { + printf("preCheck Img edge error..... %s \n", tem.strPath.c_str()); + InsertDetResult(tem); + return ERROR_PRECHECK_IMG_NULL; + } + + tem.status = 2; + InsertDetResult(tem); + } + } + } + + return 0; +} +int deal::SetStatus(int type, int status) +{ + std::lock_guard lock(mtx_List[Mutex_Type_DetStatus]); + m_DetStatusList[type] = status; + + return 0; +} +int deal::GetStatus(int type) +{ + std::lock_guard lock(mtx_List[Mutex_Type_DetStatus]); + + return m_DetStatusList[type]; +} +bool deal::IsStatus(int type, int status) +{ + std::lock_guard lock(mtx_List[Mutex_Type_DetStatus]); + if (m_DetStatusList[type] == status) + { + return true; + } + + return false; +} +int deal::SetStatus_List(int idx, Thread_Status_ status) +{ + std::lock_guard lock(mtx_List[Mutex_Type_ReadImgThread]); + m_nReadStausList[idx] = status; + return 0; +} +int deal::GetStatus_List(int idx) +{ + std::lock_guard lock(mtx_List[Mutex_Type_ReadImgThread]); + return m_nReadStausList[idx]; +} +bool deal::IsStatus_List(int idx, Thread_Status_ status) +{ + std::lock_guard lock(mtx_List[Mutex_Type_ReadImgThread]); + if (idx < 0 || idx >= READ_IMG_THREAD_NUM) + { + } + else + { + if (m_nReadStausList[idx] == status) + { + return true; + } + } + + return false; +} + +int deal::setReadThreadStart() +{ + for (int i = 0; i < READ_IMG_THREAD_NUM; i++) + { + SetStatus_List(i, Thread_Status_READY); + } + return 0; +} + +int deal::GetReadImgCompleteThreadIdx() +{ + for (int i = 0; i < READ_IMG_THREAD_NUM; i++) + { + if (IsStatus_List(i, Thread_Status_COMMPLET)) + { + return i; + } + } + return -1; +} + +bool deal::IsALLComplete() +{ + std::lock_guard lock(mtx_List[Mutex_Type_DetStatus]); + + for (size_t i = 0; i < READ_IMG_THREAD_NUM; i++) + { + if (m_nReadStausList[i] == ReadImg_Status_COMMPLET) + { + return false; + } + } + return true; +} + +int deal::InitCPUIDX() +{ + int start = 3; + m_CPUInfo[THREAD_CPU_Main_Det].set(start, 4); + start += 4; + m_CPUInfo[THREAD_CPU_Main_readImg].set(start, READ_IMG_THREAD_NUM); + start += READ_IMG_THREAD_NUM; + m_CPUInfo[THREAD_CPU_Main_saveImg].set(start, Save_IMG_THREAD_NUM); + start += Save_IMG_THREAD_NUM; + m_CPUInfo[THREAD_CPU_CheckSo].set(start, 15); + return 0; +} + +void deal::Thread_ReadImg(int id) +{ + if (!IsStatus_List(id, Thread_Status_READY)) + { + return; + } + + int re = 0; + std::shared_ptr pImageInfo = nullptr; + re = GetReadImgInfo(pImageInfo); + if (pImageInfo == nullptr) + { + printf("pImageInfo == nullptr=================id %d=============\n", id); + return; + } + // pImageInfo->img = cv::imread(pImageInfo->strPath, 0); + m_pextractImg->ReadCELLImg(pImageInfo->strPath, pImageInfo->img, runConfig.bdecode); + // cv::imwrite(pImageInfo->strchannelName + "_A_ssssde.png", pImageInfo->img); + if (pImageInfo->strPath_B != "") + { + m_pextractImg->ReadCELLImg(pImageInfo->strPath_B, pImageInfo->img_B, runConfig.bdecode); + // cv::imwrite(pImageInfo->strchannelName + "_B_sssde.png", pImageInfo->img_B); + } + + m_ReadImgThread_Result[id] = pImageInfo; + + // 线程完成读图,设置现场状态为 完成 + SetStatus_List(id, Thread_Status_COMMPLET); + + // printf("Thread_ReadImg=================id %d %s=============\n", id, pImageInfo->strPath.c_str()); +} + +int deal::InsertReadImgInfo(std::shared_ptr pImageInfo) +{ + std::lock_guard lock(mutex_ReadImgList); + m_ReadImg_queue.push(pImageInfo); + cv_ReadImgList.notify_one(); // 唤醒等待的线程 + return 0; +} + +int deal::GetReadImgInfo(std::shared_ptr &pImageInfo) +{ + // printf("===============waite img info ===============\n"); + std::unique_lock lock(mutex_ReadImgList); + + cv_ReadImgList.wait(lock, [this]() + { return !m_ReadImg_queue.empty(); }); + + pImageInfo = m_ReadImg_queue.front(); // 获取队首数据 + if (pImageInfo == NULL) + { + return 1; + } + m_ReadImg_queue.pop(); // 弹出队首数据 + return 0; +} + +int deal::LoadOfflineCheckImg(std::string strImgPath) +{ + std::vector img_paths; + cv::glob(strImgPath, img_paths, true); + m_OffLineCheckImgList.erase(m_OffLineCheckImgList.begin(), m_OffLineCheckImgList.end()); + m_OffLineCheckImgNameList.erase(m_OffLineCheckImgNameList.begin(), m_OffLineCheckImgNameList.end()); + for (int i = 0; i < img_paths.size(); i++) + { + + size_t found = img_paths[i].find_last_of("/\\"); + + // std::cout << img_paths[i] << std::endl; + std::string str = img_paths[i]; + m_OffLineCheckImgNameList.push_back(str); + } + return 0; +} +int deal::LoadImgPath_JCSN(std::string strImgPath) +{ + + std::cout << strImgPath << std::endl; + std::vector img_paths; + + cv::glob(strImgPath, img_paths, true); + + m_OffImageSNPathList.erase(m_OffImageSNPathList.begin(), m_OffImageSNPathList.end()); + + for (int i = 0; i < img_paths.size(); i++) + { + + std::string path = img_paths[i]; + // std::cout << img_paths[i] << std::endl; + + // 提取所有文件夹名称 + std::vector allDirectories = extractAllDirectories(path); + std::string strSN = ""; + // 输出所有文件夹名称 + std::string strAllPath = "/"; + + for (const auto &dir : allDirectories) + { + strAllPath += dir; + if (isValidString(dir)) + { + strSN = dir; + // std::cout << strSN << std::endl; + break; + } + strAllPath += "/"; + } + + bool bh = false; + for (int j = 0; j < m_OffImageSNPathList.size(); j++) + { + if (m_OffImageSNPathList.at(j) == strAllPath) + { + bh = true; + break; + } + } + if (!bh) + { + if (m_OffImageSNPathList.size() < m_nTestNum) + { + m_OffImageSNPathList.push_back(strAllPath); + std::cout << strAllPath << std::endl; + } + + // std::cout << strSN << std::endl; + } + } + + return 0; +} + +bool deal::isValidString(const std::string &str) +{ + // 检查字符串长度是否为10 + if (str.length() < 14 || str.length() > 19) + { + return false; + } + + // 检查字符串中的每个字符是否都是字母或数字 + for (char c : str) + { + if (!std::isalnum(c)) + { // 如果字符不是字母或数字 + return false; + } + } + + // 字符串满足条件 + return true; +} +int deal::LoadProductID(std::string strImgPath) +{ + m_product_ID_List.erase(m_product_ID_List.begin(), m_product_ID_List.end()); + std::vector img_paths; + + // tif 格式 + { + std::string str_bmp = strImgPath + "/*.ytimage"; + if(!runConfig.bdecode) + { + str_bmp = strImgPath + "/*.jpg"; + } + std::cout << str_bmp << std::endl; + + cv::glob(str_bmp, img_paths, true); + for (int i = 0; i < img_paths.size(); i++) + { + + std::string path = img_paths[i]; + // 提取所有文件夹名称 + std::vector allDirectories = extractAllDirectories(path); + std::string strSN = ""; + // 输出所有文件夹名称 + std::string strAllPath = "/"; + + for (const auto &dir : allDirectories) + { + // std::cout << dir << std::endl; + strAllPath += dir; + if (isValidString(dir)) + { + strSN = dir; + break; + } + strAllPath += "/"; + } + + bool bh = false; + for (int j = 0; j < m_product_ID_List.size(); j++) + { + if (m_product_ID_List.at(j) == strAllPath) + { + bh = true; + break; + } + } + if (!bh) + { + if (m_product_ID_List.size() < m_nTestNum) + { + m_product_ID_List.push_back(strAllPath); + std::cout << strAllPath << std::endl; + } + } + } + } + + return 0; +} +int deal::DelImg_Cell_ET() +{ + + size_t totalSize = m_product_ID_List.size(); + if (totalSize > 0) + { + m_DetResult.Init(); + /* code */ + } + + for (size_t idx = 0; idx < totalSize; idx++) + { + string cur_time = CheckUtil::getCurTimeHMS(); + printf("[%s]>>> %zu / %zu %s----start \n", cur_time.c_str(), idx, totalSize, m_product_ID_List.at(idx).c_str()); + long t1, t2; + t1 = getcurTime(); + Det_OneProduct_Cell_ET(m_product_ID_List.at(idx), idx); + t2 = getcurTime(); + string cur_time_end = CheckUtil::getCurTimeHMS(); + printf("[%s]>>> %zu / %zu %s----End use time %ld\n", cur_time_end.c_str(), idx, totalSize, m_product_ID_List.at(idx).c_str(), t2 - t1); + } + if (totalSize > 0) + { + // 等待所有检测都完成 + while (true) + { + usleep(1000 * 1000 * 10); + printf("len %zu \n", m_Result_list.size()); + if (m_Result_list.size() <= 0) + { + printf("check =============== complete \n"); + break; + } + } + } + m_product_ID_List.erase(m_product_ID_List.begin(), m_product_ID_List.end()); + m_product_ID_List.clear(); + return RESULT_OK; +} +int deal::Det_OneProduct_Cell_ET(std::string strProductName, int Idx) +{ + + std::string strProductID = GetFileName(strProductName); + + // 获取图片路径 + std::vector detImgInfoList; + string strSearchImg = strProductName; + + int re = GetDetImageInfo(strProductID, strSearchImg, detImgInfoList); + if (re != 0) + { + return re; + } + // 没有图片 + if (detImgInfoList.size() <= 0) + { + return 1; + } + + // 读图现场都开启 + setReadThreadStart(); + int AllImgNum = detImgInfoList.size(); + + // 遍历所有图片 开始读图处理 + for (int i = 0; i < detImgInfoList.size(); i++) + { + std::shared_ptr tem = std::make_shared(); + tem->copy(detImgInfoList.at(i)); + InsertReadImgInfo(tem); + } + m_DetResult.startTime_S = getcurTime(); + IN_IMG_Status_ temstatus = IN_IMG_Status_Start; + + std::shared_ptr tempDetImageInfo = nullptr; + + Det_One_Result_Info tem_one; + tem_one.Product_ID = strProductID; + tem_one.result = 0; + long ts = getcurTime(); + tem_one.time_s = ts; + + int GetImgNum = 0; + while (true) + { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); // 模拟消费过程 + int ThreadIdx = GetReadImgCompleteThreadIdx(); + if (ThreadIdx < 0) + { + continue; + } + std::shared_ptr pDetImageInfo = nullptr; + pDetImageInfo = m_ReadImgThread_Result[ThreadIdx]; + + // 开始送到检测进行处理 + if (pDetImageInfo != nullptr) + { + // printf(">>> %s----start \n", pDetImageInfo->strName.c_str()); + tempDetImageInfo = pDetImageInfo; + int re = SendImgToCheck(pDetImageInfo, temstatus); + if (re != 0) + { + continue; + } + Det_single_img_Result_Info tem_single; + tem_single.name = pDetImageInfo->strchannelName; + tem_single.result = -1; + tem_one.img_result_list.push_back(tem_single); + } + SetStatus_List(ThreadIdx, Thread_Status_READY); + GetImgNum++; + + if (IN_IMG_Status_Start == temstatus) + { + temstatus = IN_IMG_Status_Other; + } + + // 图是否都读取完了。 + bool bReadCompleted = false; + + if (GetImgNum >= AllImgNum) + { + bReadCompleted = true; + } + + // 退出 + if (bReadCompleted) + { + SendImgToCheck(tempDetImageInfo, IN_IMG_Status_End); + break; + } + } + + m_DetResult.one_result_list.push_back(tem_one); + m_DetResult.det_num_all++; + // if (m_DetResult.det_num_all == 1) + // { + + // } + // printf("startTime_S==== %ld \n", m_DetResult.startTime_S); + // getchar(); + return 0; +} +int deal::Det_Edge_Test_OneImg() +{ + + int imgNum = 0; + std::string strchannel = "L255"; + std::string str = runConfig.filePath + "/*" + strchannel + ".tif"; + { + std::cout << str << std::endl; + m_OffImageSNPathList.erase(m_OffImageSNPathList.begin(), m_OffImageSNPathList.end()); + + cv::glob(str, m_OffImageSNPathList, true); + } + + imgNum = m_OffImageSNPathList.size(); + if (imgNum > m_nTestNum && m_nTestNum > 0) + { + imgNum = m_nTestNum; + } + + printf("Img Num %d \n", imgNum); + if (imgNum <= 0) + { + return 0; + } + + for (int i = 0; i < m_OffImageSNPathList.size(); i++) + { + printf(">>> %d / %zu --start \n", i, m_OffImageSNPathList.size()); + long t1, t2; + cv::Mat detimg = cv::imread(m_OffImageSNPathList.at(i)); + { + std::shared_ptr result; + + std::shared_ptr temdet = std::make_shared(); + if (m_nSaveDetprocessImg == 1) + { + temdet->otherValue = 9; + } + temdet->strImgName = "test"; + temdet->strImgProductID = "test"; + temdet->strChannel = "L255"; + + if (runConfig.det_Type == RUNTYPE_RUN_EDGE_TEST || + runConfig.det_Type == RUNTYPE_RUN_EDGE_TEST_AI) + { + temdet->Det_Mode = DET_MODE_EDGE; + if (runConfig.det_Type == RUNTYPE_RUN_EDGE_TEST_AI) + { + temdet->ninstruct = 999; + } + } + + temdet->img = detimg; + + m_pALLImgCheckAnalysisy->CheckImg(temdet, result); + // 结果异常 + } + } + + return 0; +} +int deal::Det_Funtion_Test() +{ + int re = 0; + + if (runConfig.det_Type == RUNTYPE_RUN_EDGE_TEST || + runConfig.det_Type == RUNTYPE_RUN_EDGE_TEST_AI) + { + + Det_Funtion_Edge(); + return 0; + } + + // 获取图片 + + return 0; +} +int deal::Det_Funtion_Edge() +{ + + int imgNum = 0; + std::string strchannel = "L255"; + std::string str = runConfig.filePath + "/*" + strchannel + ".tif"; + + { + std::cout << str << std::endl; + m_OffImageSNPathList.erase(m_OffImageSNPathList.begin(), m_OffImageSNPathList.end()); + + cv::glob(str, m_OffImageSNPathList, true); + } + + imgNum = m_OffImageSNPathList.size(); + if (imgNum > m_nTestNum && m_nTestNum > 0) + { + imgNum = m_nTestNum; + } + printf("Img Num %d \n", imgNum); + if (imgNum <= 0) + { + return 0; + } + + // 读图现场都开启 + setReadThreadStart(); + int AllImgNum = imgNum; + + // 遍历所有图片 开始读图处理 + for (int i = 0; i < imgNum; i++) + { + std::shared_ptr tem = std::make_shared(); + tem->strPath = m_OffImageSNPathList.at(i); + tem->strchannelName = strchannel; + InsertReadImgInfo(tem); + } + int GetImgNum = 0; + while (true) + { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); // 模拟消费过程 + int ThreadIdx = GetReadImgCompleteThreadIdx(); + if (ThreadIdx < 0) + { + continue; + } + + std::shared_ptr pDetImageInfo = nullptr; + pDetImageInfo = m_ReadImgThread_Result[ThreadIdx]; + + SetStatus_List(ThreadIdx, Thread_Status_READY); + GetImgNum++; + + // 开始送到检测进行处理 + if (pDetImageInfo == nullptr) + { + continue; + } + // printf("GetImgNum:111111111111111 %d\n", GetImgNum); + { + std::shared_ptr result; + + std::shared_ptr temdet = std::make_shared(); + if (m_nSaveDetprocessImg == 1) + { + temdet->otherValue = 9; + } + temdet->strImgName = "test"; + temdet->strImgProductID = "test"; + temdet->strChannel = strchannel; + + if (runConfig.det_Type == RUNTYPE_RUN_EDGE_TEST || + runConfig.det_Type == RUNTYPE_RUN_EDGE_TEST_AI) + { + temdet->Det_Mode = DET_MODE_EDGE; + if (runConfig.det_Type == RUNTYPE_RUN_EDGE_TEST_AI) + { + temdet->ninstruct = 999; + } + } + + temdet->img = pDetImageInfo->img; + + m_pALLImgCheckAnalysisy->CheckImg(temdet, result); + // 结果异常 + } + + // 图是否都读取完了。 + if (GetImgNum >= AllImgNum) + { + break; + } + } + + return 0; +} +int deal::RandDrawImg(cv::Mat srcimg, cv::Mat &randErrorImg) +{ + + randErrorImg = srcimg.clone(); + cv::Rect roi; + roi.x = (rand() % (srcimg.cols - 20 - 20)) + 20; + roi.y = (rand() % (srcimg.rows - 20 - 20)) + 20; + roi.width = (rand() % (100 - 5)) + 5; + roi.height = roi.width; + + if (roi.x + roi.width >= srcimg.cols) + { + roi.x = srcimg.cols - roi.width - 1; + /* code */ + } + if (roi.y + roi.height >= srcimg.rows) + { + roi.y = srcimg.rows - roi.height - 1; + /* code */ + } + randErrorImg(roi).setTo(30); + return 0; +} +void deal::DealImg() +{ + // 线程送图处理: + std::vector vi; + int startidx = m_CPUInfo[THREAD_CPU_Main_Det].startIdx; + int cpunum = m_CPUInfo[THREAD_CPU_Main_Det].num; + for (int i = 0; i < cpunum; i++) + { + vi.push_back(startidx + i); + } + auto nRet = set_cpu_id(vi); + printf("THREAD_CPU_Main_Det bind cpu ret %d startidx %d num %d\n", nRet, startidx, cpunum); + int re = 0; + while (!m_bExit) + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟消费过程 + re = DelImg_Cell_ET(); + } +} +// 提取所有文件夹名称函数 +std::vector deal::extractAllDirectories(const std::string &path) +{ + std::vector directories; + std::string directory; + + // 遍历路径中的每个字符 + for (char c : path) + { + // 如果遇到路径分隔符,则将当前文件夹名称存储起来 + if (c == '/' || c == '\\') + { + if (!directory.empty()) + { // 确保文件夹名称不为空 + directories.push_back(directory); + directory.clear(); // 清空当前文件夹名称 + } + } + else + { + directory += c; // 将字符添加到当前文件夹名称中 + } + } + + // 将最后一个文件夹名称添加到列表中 + if (!directory.empty()) + { + directories.push_back(directory); + } + + return directories; +} \ No newline at end of file diff --git a/example/deal.h b/example/deal.h new file mode 100644 index 0000000..1821932 --- /dev/null +++ b/example/deal.h @@ -0,0 +1,727 @@ + +#ifndef _deal_HPP_ +#define _deal_HPP_ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "SystemCommonDefine.h" +#include "ImgCheckBase.h" +#include "ImgCheckConfig.h" + +#include "ConfigBase.h" +#include +#include +#include +#include "Image_ReadAndChange.h" + +#include "ExtractBase.h" +#include +#include "Read_Image.h" + +namespace fs = std::filesystem; + +enum Thread_Status_ +{ + Thread_Status_IDE, + Thread_Status_READY, + Thread_Status_BUSY, + Thread_Status_COMMPLET, +}; +enum Thread_ReadImg_Status_ +{ + ReadImg_Status_IDE, + ReadImg_Status_Read, + ReadImg_Status_COMMPLET, +}; + +// 各种线程处理状态信息 +enum DET_Status_Type_ +{ + Status_Type_ReadAndDet, // 读取图和处理 + Status_Type_PullPath, // 读取图片路径 + Status_Type_Count, +}; + +enum Mutex_Type_ +{ + Mutex_Type_ReadImgThread, // 读图线程 + Mutex_Type_DetStatus, + Mutex_Type_DetResult, + Mutex_Type_Count, +}; +// 读线程,处理类型。 +enum READ_THREAD_TYPE_ +{ + READ_THREAD_TYPE_NULL, + READ_THREAD_TYPE_READIMG, // 读图 + READ_THREAD_Detect, // 检测模式 + READ_THREAD_TYPE_COUNT, +}; + +// 线程运行模式 +enum THREAD_RUN_TYPE +{ + THREAD_RUN_Only_ReadImg, // 仅读图 + THREAD_RUN_ALL, // 所有 +}; + +#define READ_IMG_THREAD_NUM 4 +#define Save_IMG_THREAD_NUM 4 + +using namespace std; +enum RUNTYPE_ +{ + RUNTYPE_RUN_Pre, + RUNTYPE_RUN_File, + RUNTYPE_RUN_EDGE_TEST, + RUNTYPE_RUN_EDGE_TEST_AI, + RUNTYPE_RUN_Merge_Img, +}; +// 程序运行模式 +enum Process_Run_Type +{ + Process_Run_Detect, // 正常检测模式 + Process_Run_ReJson, // 复测模式 + Process_Run_SaveImg, // 解密图片并存图 +}; + +struct JC_IMAGE_INFO_ +{ + enum Status_ + { + STATUS_Image_IDE, + STATUS_Image_READ, + STATUS_Image_COMMPLET, + STATUS_Det_Start, + }; + std::string strProductID; // 产品ID + std::string strCamID; // 相机名称 + std::string strchannelName; // 通道名称 + std::string strPath; // 完整路径 + std::string strPath_B; // 完整路径 + std::string strName; // 图片名称 + cv::Mat img; // 图像数据 + cv::Mat img_B; // 图像数据 + Status_ status; // 状态 + long readImg_start; // 读取开始时间 + long readImg_end; // 读取结束时间 + + // 构造函数,调用 Init 初始化 + JC_IMAGE_INFO_() + { + Init(); + } + + // 初始化函数,重置所有成员变量 + void Init() + { + strProductID = ""; + strCamID = ""; + strchannelName = ""; + strPath = ""; + strPath_B = ""; + strName = ""; + img.release(); // 释放图像内存 + status = STATUS_Image_IDE; + readImg_start = 0; + readImg_end = 0; + } + + // 拷贝函数,将传入的结构体内容复制到当前对象 + void copy(JC_IMAGE_INFO_ tem) + { + this->strProductID = tem.strProductID; + this->strCamID = tem.strCamID; + this->strchannelName = tem.strchannelName; + this->strPath = tem.strPath; + this->strPath_B = tem.strPath_B; + this->strName = tem.strName; + if (!tem.img.empty()) + { + this->img = tem.img.clone(); // 深拷贝图像数据 + } + if (!tem.img_B.empty()) + { + this->img_B = tem.img_B.clone(); // 深拷贝图像数据 + } + this->status = tem.status; + this->readImg_start = tem.readImg_start; + this->readImg_end = tem.readImg_end; + } + + // 打印信息函数(可选) + void print() + { + std::cout << "Product ID: " << strProductID << std::endl; + std::cout << "Camera ID: " << strCamID << std::endl; + std::cout << "Channel Name: " << strchannelName << std::endl; + std::cout << "Image Path: " << strPath << std::endl; + std::cout << "Image strPath_B: " << strPath_B << std::endl; + std::cout << "Image Name: " << strName << std::endl; + std::cout << "Status: " << status << std::endl; + std::cout << "Read Start Time: " << readImg_start << std::endl; + std::cout << "Read End Time: " << readImg_end << std::endl; + } +}; +struct Det_single_img_Result_Info +{ + int result; + std::string name; + std::string qx_name; + Det_single_img_Result_Info() + { + Init(); + } + void Init() + { + name = ""; + result = 0; + qx_name = "NO"; + } +}; +struct Det_One_Result_Info +{ + int result; + long time_s; + long time_e; + std::string Product_ID; + std::vector img_result_list; + Det_One_Result_Info() + { + Init(); + } + void Init() + { + Product_ID = ""; + time_s = 0; + time_e = 0; + result = 0; + img_result_list.erase(img_result_list.begin(), img_result_list.end()); + img_result_list.clear(); + } + std::string print() + { + std::string str = ""; + // printf("%s:result %d | ", Product_ID.c_str(), result); + char buffer[64]; + sprintf(buffer, "%s:result %d time %ld | ", Product_ID.c_str(), result, time_e - time_s); + std::string st1 = buffer; + str += st1; + for (size_t i = 0; i < img_result_list.size(); i++) + { + str += img_result_list.at(i).name + " " + img_result_list.at(i).qx_name + " | "; + } + // str += str; + + return str; + // printf("%s\n", str.c_str()); + } +}; +struct Det_File_qx_Info +{ + std::string qx_name; + int num; + Det_File_qx_Info() + { + Init(); + } + void Init() + { + qx_name = ""; + num = 0; + } +}; +// 套图检测 统计结果信息 +struct Det_File_Result_Info +{ + int det_num_all; + int det_num_ok; + int det_num_ng; + int det_num_error; + float sumtime_S; + long startTime_S; + float mean_time; + std::vector one_result_list; + std::vector strlist; + std::vector qx_result_list; + Det_File_Result_Info() + { + Init(); + } + void Init() + { + det_num_all = 0; + det_num_ok = 0; + det_num_ng = 0; + det_num_error = 0; + sumtime_S = 0; + startTime_S = 0; + mean_time = 0; + one_result_list.erase(one_result_list.begin(), one_result_list.end()); + one_result_list.clear(); + strlist.erase(strlist.begin(), strlist.end()); + strlist.clear(); + qx_result_list.erase(qx_result_list.begin(), qx_result_list.end()); + qx_result_list.clear(); + } + void updata(std::string productid, std::string imgname, int nresult, long t) + { + sumtime_S = t - startTime_S; + sumtime_S /= 1000; + if (det_num_all > 0) + { + mean_time = sumtime_S / det_num_all; + } + + for (int i = 0; i < one_result_list.size(); i++) + { + if (one_result_list.at(i).Product_ID == productid) + { + // if (one_result_list.at(i).result < 0) + // { + // one_result_list.at(i).result = 0; + // } + one_result_list.at(i).time_e = t; + + for (size_t j = 0; j < one_result_list.at(i).img_result_list.size(); j++) + { + if (one_result_list.at(i).img_result_list.at(j).name == imgname) + { + one_result_list.at(i).img_result_list.at(j).result = nresult; + if (nresult == 0) + { + one_result_list.at(i).img_result_list.at(j).qx_name = "OK"; + } + else if (nresult > 0) + { + one_result_list.at(i).img_result_list.at(j).qx_name = "NG"; + if (one_result_list.at(i).result == 0) + { + one_result_list.at(i).result = 1; + } + } + else + { + one_result_list.at(i).img_result_list.at(j).qx_name = "ER"; + one_result_list.at(i).result = -1; + } + } + } + } + } + } + void update_qx(std::string qx_name, int num) + { + for (int i = 0; i < qx_result_list.size(); i++) + { + if (qx_result_list.at(i).qx_name == qx_name) + { + qx_result_list.at(i).num += num; + return; + } + } + Det_File_qx_Info tem; + tem.qx_name = qx_name; + tem.num = num; + qx_result_list.push_back(tem); + } + void print(bool show = true) + { + + strlist.erase(strlist.begin(), strlist.end()); + strlist.clear(); + det_num_ok = 0; + det_num_ng = 0; + det_num_error = 0; + std::string str = ""; + str = "*****************************************************************************"; + strlist.push_back(str); + + str = "*****************************detect result***********************************"; + strlist.push_back(str); + + float fok = 0; + float fng = 0; + float ferror = 0; + // printf("one_result_list.size() %d \n", one_result_list.size()); + for (int i = 0; i < one_result_list.size(); i++) + { + if (one_result_list.at(i).result == 0) + { + det_num_ok++; + } + else if (one_result_list.at(i).result > 0) + { + det_num_ng++; + } + else + { + det_num_error++; + } + } + if (det_num_all > 0) + { + fok = det_num_ok * 1.0f / det_num_all * 100; + fng = det_num_ng * 1.0f / det_num_all * 100; + ferror = det_num_error * 1.0f / det_num_all * 100; + } + char buffer[64]; + sprintf(buffer, "ALL:%d OK:%d %.1f%% NG:%d %.1f%% Error:%d %.1f%%", det_num_all, det_num_ok, fok, det_num_ng, fng, det_num_error, ferror); + std::string st1 = buffer; + strlist.push_back(st1); + sprintf(buffer, "Use time %f s mean time %f s", sumtime_S, mean_time); + std::string st2 = buffer; + + strlist.push_back(st2); + // printf("%s\n", st1.c_str()); + // printf("------------------------------------------------------------------------------\n"); + str = "------------------------------------------------------------------------------"; + strlist.push_back(str); + + { + int qx_all_num = 0; + for (size_t i = 0; i < qx_result_list.size(); i++) + { + qx_all_num += qx_result_list.at(i).num; + } + for (size_t i = 0; i < qx_result_list.size(); i++) + { + float fr = qx_result_list.at(i).num * 1.0 / qx_all_num * 100; + std::string str_qx = ""; + // printf("len %d \n", qx_result_list.at(i).qx_name.length()); + for (int k = 0; k < (20 - qx_result_list.at(i).qx_name.length()); k++) + { + str_qx += " "; + } + str_qx += qx_result_list.at(i).qx_name; + char buffer123[64]; + sprintf(buffer123, ":%d %.1f%% ", qx_result_list.at(i).num, fr); + std::string st1 = buffer123; + str_qx += st1; + int nlen = fr; + + for (int j = 0; j < nlen; j++) + { + str_qx += "|"; + } + strlist.push_back(str_qx); + } + } + + str = "------------------------------------------------------------------------------"; + strlist.push_back(str); + + for (int i = 0; i < one_result_list.size(); i++) + { + st1 = one_result_list.at(i).print(); + strlist.push_back(st1); + } + str = "*****************************************************************************"; + strlist.push_back(str); + // printf("*****************************************************************************\n"); + if (show) + { + for (size_t i = 0; i < strlist.size(); i++) + { + printf("%s\n", strlist.at(i).c_str()); + } + } + } +}; +struct IMG_BASE_INFO_ +{ + std::string strPath; + std::string strChannel; + std::string strImgSN; + IMG_BASE_INFO_() + { + strPath = ""; + strImgSN = ""; + strChannel = ""; + } +}; +struct ReadImgInfo +{ + std::string strPath; + std::string strChannel; + int stype; + int status; + std::string strImgSN; + int idx; + int sumNUm; + cv::Rect cutRoi; + std::vector imglist; + ReadImgInfo() + { + strPath = ""; + strImgSN = ""; + stype = 0; + status = 0; + idx = 0; + imglist.clear(); + cutRoi = cv::Rect(0, 0, 0, 0); + sumNUm = 0; + } +}; + +struct AI_Det_Path +{ + std::string strPath_CutImg; + std::string strPath_AIMask; + /* data */ +}; +struct AI_Det_Channel_ +{ + std::string strChannel; + AI_Det_Path path; + /* data */ +}; +struct Json_Det_Path +{ + std::string strPath_CutImg; + std::string strPath_Json; + /* data */ +}; +struct READ_IMG_INFO +{ + std::string strpath = ""; + std::string strpath_2 = ""; + std::string strproduct = ""; +}; +struct DealRunConfig +{ + Process_Run_Type run_Type = Process_Run_Detect; // 运行模式 + RUNTYPE_ det_Type = RUNTYPE_RUN_Pre; // 处理 + std::string filePath = ""; // 处理文件路径 如果为空 处理当前的单张图片 + bool bSaveProcessImg = false; // 是否中间图片图片 + bool bdecode = true; // 读图是否解密 + void print(std::string str) + { + printf(">>>>>>>>>>>>>>> %s <<<<<<<<<<<<\n", str.c_str()); + + printf("run_Type %d det_Type %d file %s bsave %d \n", run_Type, det_Type, filePath.c_str(), bSaveProcessImg); + } +}; +class deal +{ +public: + // 构造函数 + deal(); + ~deal(); + int start(); + +private: + // 初始化 + int Init(); + // 检测参数 + int LoadCheckImgConfig(); + + // 初始化检测分析线程类 + int InitCheckAnalysisy(); + int InitConfig(); + int InitExtractImg(); + // 初始化 检查存图路径 + int InitSaveImgPath(); + + int LoadCheckConfig(); + // 分析参数 + int LoadAnalysisConfig(); + // 开启线程 + int StartThread(THREAD_RUN_TYPE type); + // 停止线程 + int StopThread(); + + int preCheck(); + int Testsaveimg(); + std::string readTestImg(); + int readTestImg(READ_IMG_INFO &read); + // 重复检测 + int repeatCheck(); + int saveImg(std::string strpath, std::shared_ptr result); + int writeLog(std::string strSavePath, std::vector logList); + int WriteJsonString(std::string strSavePath, std::string strjson); + + int DelImg_Cell_ET(); + int Det_OneProduct_Cell_ET(std::string strProductName, int Idx); + + // 获取图片路径 + int GetDetImageInfo(std::string strProductID, std::string strSearchImg, std::vector &jcImageInfoList); + // 解析图片的信息 -- cell et + int GetImgInfo_POL_ET(std::string strImgPath, JC_IMAGE_INFO_ *pImageInfo); + + int GetImgInfo_POL_ET_PNG(std::string strImgPath, JC_IMAGE_INFO_ *pImageInfo); + + int Det_Edge_Test_OneImg(); + + // 功能测试 + int Det_Funtion_Test(); + // 边缘测试 + int Det_Funtion_Edge(); + + // 随机绘制错误 + int RandDrawImg(cv::Mat srcimg, cv::Mat &randErrorImg); + + int LoadOfflineCheckImg(std::string strImgPath); + int LoadImgPath_JCSN(std::string strImgPath); + bool isValidString(const std::string &str); + + int LoadProductID(std::string strImgPath); + + int set_cpu_id(const std::vector &cpu_set_vec); + void GetDealResultToQueu(); + // 加载系统配置文件 + bool ReadSystemConfig(const std::string &strPath); + int GetJcImageInfo(std::string strpath, std::vector &jcImageInfoList); + + int ReadTestImgaData(); + // 处理前,初始化部分数据 + int InitDetData(); + // 检测结果 插入结果队列 + int InsertDetResult(ReadImgInfo tem); + int GetUpMaskImg(cv::Mat inImg, cv::Rect roi, cv::Mat &maskimg); + + // 送图去检测 + int SendImgToCheck(std::shared_ptr pDetImageInfo, IN_IMG_Status_ status); + int ReJson(); + int ReJson_ALL(); + int DetImg(); // 套图复测 + int ReJson_product(std::vector &jsonList, std::string strProductName); // 套图复测 +private: + // 处理调度线程 + std::shared_ptr ptr_DealImgthread; + + void DealImg(); + + std::vector extractAllDirectories(const std::string &path); + + // 结果处理线程 + // std::shared_ptr ptr_Resultthread; + std::vector> ptr_ResultthreadList; + void ResultThread(int id); + + // 结果拷贝线程 + std::shared_ptr ptr_GetResultthread; + + void GetResultThread(); + + std::vector> threadArray; + + void ReadImgThread(int id); + + void testimg(cv::Mat img); + + int updataResltInfo(std::shared_ptr result); + + void slidingWindowAutoThreshold(const cv::Mat &src, cv::Mat &dst, int windowSize, int step, double C); + + int testimgUP(cv::Mat img); + int test_ZF(ReadImgInfo tem, int id); + int SetStatus(int type, int status); + int GetStatus(int type); + bool IsStatus(int type, int status); + + int SetStatus_List(int idx, Thread_Status_ status); + int GetStatus_List(int idx); + bool IsStatus_List(int idx, Thread_Status_ status); + int setReadThreadStart(); + int GetReadImgCompleteThreadIdx(); // 获取读取完成后的idx + bool IsALLComplete(); + int InitCPUIDX(); + + // 线程读图 + void Thread_ReadImg(int id); + + int InsertReadImgInfo(std::shared_ptr pImageInfo); + int GetReadImgInfo(std::shared_ptr &pImageInfo); + +public: + std::vector m_OffLineCheckImgList; // 离线检测图片列表 + std::vector m_OffLineCheckImgNameList; // 离线检测图片列表 + std::vector m_OffImageSNPathList; // 离线检测图片列表 + std::vector m_product_ID_List; // 离线检测图片列表 + + ALLImgCheckBase *m_pALLImgCheckAnalysisy; + + std::vector m_TestJC_ImageDate; // 离线检测图片列表 + std::string m_strCurDate; + int m_nSystemCheckType; + bool m_bExit; + int nLastCheckAnalysisyThreadIdx; + + RunInfoST m_RunConfig; // 检测基本参数 + + std::mutex mutex_Result_list; + std::queue> m_Result_list; + + // 检测区域list + std::vector m_DetRoiMaskPointList; + // 检测区域list + std::vector m_CoreMaskPointList; + + DealRunConfig runConfig; + + int m_nTestNum; + + std::string m_strSaveImgPath; + + ConfigManagerBase *m_pConfigManager = NULL; + + SystemConfigParam m_system_param; + int m_nCurUseCPUIDX; + int m_nCamIdx; + ImageInfo m_ImgInfo_src; + ImageInfo m_ImgInfo_result; + + int m_nSaveDetprocessImg; + cv::Rect m_CutRoi; + + ExtractBase *m_pextractImg; + int nn; + int nddd; + int kkd; + int maxidx; + + Det_File_Result_Info m_DetResult; + std::vector m_ImageInfoList; + + std::queue> m_ReadImg_queue; // 读图队列 + + std::mutex mutex_ReadImgList; + std::condition_variable cv_ReadImgList; + + int m_nReadStausList[READ_IMG_THREAD_NUM]; + // 读图线程状态 + std::shared_ptr m_ReadImgThread_Result[READ_IMG_THREAD_NUM]; + + READ_THREAD_TYPE_ m_nReadThread_type; + bool m_nreadImg_Stop; + std::mutex mutex_DetResult_; + + std::queue m_DetImgQueue; // 存储生产者生产的数据 + std::mutex mtx_DetImgQueue; // 互斥量,保护共享资源 + std::mutex mtx_DetImgQueue_edge; // 互斥量,保护共享资源 + std::condition_variable cv; // 条件变量,用于线程间通信 + + std::mutex mtx_DetImgQueue_com; // + int m_read_ImgNum; + long m_readImgStarttime; + + int m_DetStatusList[Status_Type_Count]; // 各种需要线程同步的状态信息 + std::mutex mtx_List[Mutex_Type_Count]; // 互斥量 + std::vector m_DetResultList; + + CPU_ID_INFO_ m_CPUInfo[THREAD_CPU_Count]; + + Image_ReadChannel m_image_ReadChannel; + + Process_Run_Type m_processRunType = Process_Run_Detect; // 程序运行模式 +}; + +#endif //_CORELOGICFACTORY_HPP_ \ No newline at end of file diff --git a/example/json/json-forwards.h b/example/json/json-forwards.h new file mode 100644 index 0000000..45d2e46 --- /dev/null +++ b/example/json/json-forwards.h @@ -0,0 +1,346 @@ +/// Json-cpp amalgamated forward header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json-forwards.h" +/// This header provides forward declaration for all JsonCpp types. + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED +# define JSON_FORWARD_AMALGAMATED_H_INCLUDED +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +#define JSON_IS_AMALGAMATION + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED +#include +#include //typedef int64_t, uint64_t +#include //typedef String + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of +/// std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgamated header. +// #define JSON_IS_AMALGAMATION + +#ifdef JSON_IN_CPPTL +#include +#ifndef JSON_USE_CPPTL +#define JSON_USE_CPPTL 1 +#endif +#endif + +#ifdef JSON_IN_CPPTL +#define JSON_API CPPTL_API +#elif defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#define JSON_API +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +#if defined(_MSC_VER) // MSVC +#if _MSC_VER <= 1200 // MSVC 6 +// Microsoft Visual Studio 6 only support conversion from __int64 to double +// (no conversion from unsigned __int64). +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' +// characters in the debug information) +// All projects I've ever seen with VS6 were using this globally (not bothering +// with pragma push/pop). +#pragma warning(disable : 4786) +#endif // MSVC 6 + +#if _MSC_VER >= 1500 // MSVC 2008 + /// Indicates that the following function is deprecated. +#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#endif + +#endif // defined(_MSC_VER) + +// In c++11 the override keyword allows you to explicitly define that a function +// is intended to override the base-class version. This makes the code more +// manageable and fixes a set of common hard-to-find bugs. +#if __cplusplus >= 201103L +#define JSONCPP_OVERRIDE override +#define JSONCPP_NOEXCEPT noexcept +#define JSONCPP_OP_EXPLICIT explicit +#elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900 +#define JSONCPP_OVERRIDE override +#define JSONCPP_NOEXCEPT throw() +#if _MSC_VER >= 1800 // MSVC 2013 +#define JSONCPP_OP_EXPLICIT explicit +#else +#define JSONCPP_OP_EXPLICIT +#endif +#elif defined(_MSC_VER) && _MSC_VER >= 1900 +#define JSONCPP_OVERRIDE override +#define JSONCPP_NOEXCEPT noexcept +#define JSONCPP_OP_EXPLICIT explicit +#else +#define JSONCPP_OVERRIDE +#define JSONCPP_NOEXCEPT throw() +#define JSONCPP_OP_EXPLICIT +#endif + +#ifndef JSON_HAS_RVALUE_REFERENCES + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // MSVC >= 2010 + +#ifdef __clang__ +#if __has_feature(cxx_rvalue_references) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // has_feature + +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // GXX_EXPERIMENTAL + +#endif // __clang__ || __GNUC__ + +#endif // not defined JSON_HAS_RVALUE_REFERENCES + +#ifndef JSON_HAS_RVALUE_REFERENCES +#define JSON_HAS_RVALUE_REFERENCES 0 +#endif + +#ifdef __clang__ +#if __has_extension(attribute_deprecated_with_message) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#endif +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +#endif // GNUC version +#endif // __clang__ || __GNUC__ + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if __GNUC__ >= 6 +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +#include "version.h" + +#if JSONCPP_USING_SECURE_MEMORY +#include "allocator.h" //typedef Allocator +#endif + +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { +typedef int Int; +typedef unsigned int UInt; +#if defined(JSON_NO_INT64) +typedef int LargestInt; +typedef unsigned int LargestUInt; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else // if defined(_MSC_VER) // Other platforms, use long long +typedef int64_t Int64; +typedef uint64_t UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) +#if JSONCPP_USING_SECURE_MEMORY +#define JSONCPP_STRING \ + std::basic_string, Json::SecureAllocator > +#define JSONCPP_OSTRINGSTREAM \ + std::basic_ostringstream, \ + Json::SecureAllocator > +#define JSONCPP_OSTREAM std::basic_ostream > +#define JSONCPP_ISTRINGSTREAM \ + std::basic_istringstream, \ + Json::SecureAllocator > +#define JSONCPP_ISTREAM std::istream +#else +#define JSONCPP_STRING std::string +#define JSONCPP_OSTRINGSTREAM std::ostringstream +#define JSONCPP_OSTREAM std::ostream +#define JSONCPP_ISTRINGSTREAM std::istringstream +#define JSONCPP_ISTREAM std::istream +#endif // if JSONCPP_USING_SECURE_MEMORY +} // end namespace Json + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class FastWriter; +class StyledWriter; + +// reader.h +class Reader; + +// features.h +class Features; + +// value.h +typedef unsigned int ArrayIndex; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED diff --git a/example/json/json.h b/example/json/json.h new file mode 100644 index 0000000..6d9a0bc --- /dev/null +++ b/example/json/json.h @@ -0,0 +1,2268 @@ +/// Json-cpp amalgamated header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_AMALGAMATED_H_INCLUDED +# define JSON_AMALGAMATED_H_INCLUDED +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +#define JSON_IS_AMALGAMATION + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + +// DO NOT EDIT. This file (and "version") is generated by CMake. +// Run CMake configure step to update it. +#ifndef JSON_VERSION_H_INCLUDED +#define JSON_VERSION_H_INCLUDED + +#define JSONCPP_VERSION_STRING "1.8.4" +#define JSONCPP_VERSION_MAJOR 1 +#define JSONCPP_VERSION_MINOR 8 +#define JSONCPP_VERSION_PATCH 4 +#define JSONCPP_VERSION_QUALIFIER +#define JSONCPP_VERSION_HEXA \ + ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ + (JSONCPP_VERSION_PATCH << 8)) + +#ifdef JSONCPP_USING_SECURE_MEMORY +#undef JSONCPP_USING_SECURE_MEMORY +#endif +#define JSONCPP_USING_SECURE_MEMORY 0 +// If non-zero, the library zeroes any memory that it has allocated before +// it frees its memory. + +#endif // JSON_VERSION_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED +#include +#include //typedef int64_t, uint64_t +#include //typedef String + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of +/// std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgamated header. +// #define JSON_IS_AMALGAMATION + +#ifdef JSON_IN_CPPTL +#include +#ifndef JSON_USE_CPPTL +#define JSON_USE_CPPTL 1 +#endif +#endif + +#ifdef JSON_IN_CPPTL +#define JSON_API CPPTL_API +#elif defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#define JSON_API +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +#if defined(_MSC_VER) // MSVC +#if _MSC_VER <= 1200 // MSVC 6 +// Microsoft Visual Studio 6 only support conversion from __int64 to double +// (no conversion from unsigned __int64). +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' +// characters in the debug information) +// All projects I've ever seen with VS6 were using this globally (not bothering +// with pragma push/pop). +#pragma warning(disable : 4786) +#endif // MSVC 6 + +#if _MSC_VER >= 1500 // MSVC 2008 + /// Indicates that the following function is deprecated. +#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#endif + +#endif // defined(_MSC_VER) + +// In c++11 the override keyword allows you to explicitly define that a function +// is intended to override the base-class version. This makes the code more +// manageable and fixes a set of common hard-to-find bugs. +#if __cplusplus >= 201103L +#define JSONCPP_OVERRIDE override +#define JSONCPP_NOEXCEPT noexcept +#define JSONCPP_OP_EXPLICIT explicit +#elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900 +#define JSONCPP_OVERRIDE override +#define JSONCPP_NOEXCEPT throw() +#if _MSC_VER >= 1800 // MSVC 2013 +#define JSONCPP_OP_EXPLICIT explicit +#else +#define JSONCPP_OP_EXPLICIT +#endif +#elif defined(_MSC_VER) && _MSC_VER >= 1900 +#define JSONCPP_OVERRIDE override +#define JSONCPP_NOEXCEPT noexcept +#define JSONCPP_OP_EXPLICIT explicit +#else +#define JSONCPP_OVERRIDE +#define JSONCPP_NOEXCEPT throw() +#define JSONCPP_OP_EXPLICIT +#endif + +#ifndef JSON_HAS_RVALUE_REFERENCES + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // MSVC >= 2010 + +#ifdef __clang__ +#if __has_feature(cxx_rvalue_references) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // has_feature + +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // GXX_EXPERIMENTAL + +#endif // __clang__ || __GNUC__ + +#endif // not defined JSON_HAS_RVALUE_REFERENCES + +#ifndef JSON_HAS_RVALUE_REFERENCES +#define JSON_HAS_RVALUE_REFERENCES 0 +#endif + +#ifdef __clang__ +#if __has_extension(attribute_deprecated_with_message) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#endif +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +#endif // GNUC version +#endif // __clang__ || __GNUC__ + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if __GNUC__ >= 6 +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +#include "version.h" + +#if JSONCPP_USING_SECURE_MEMORY +#include "allocator.h" //typedef Allocator +#endif + +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { +typedef int Int; +typedef unsigned int UInt; +#if defined(JSON_NO_INT64) +typedef int LargestInt; +typedef unsigned int LargestUInt; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else // if defined(_MSC_VER) // Other platforms, use long long +typedef int64_t Int64; +typedef uint64_t UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) +#if JSONCPP_USING_SECURE_MEMORY +#define JSONCPP_STRING \ + std::basic_string, Json::SecureAllocator > +#define JSONCPP_OSTRINGSTREAM \ + std::basic_ostringstream, \ + Json::SecureAllocator > +#define JSONCPP_OSTREAM std::basic_ostream > +#define JSONCPP_ISTRINGSTREAM \ + std::basic_istringstream, \ + Json::SecureAllocator > +#define JSONCPP_ISTREAM std::istream +#else +#define JSONCPP_STRING std::string +#define JSONCPP_OSTRINGSTREAM std::ostringstream +#define JSONCPP_OSTREAM std::ostream +#define JSONCPP_ISTRINGSTREAM std::istringstream +#define JSONCPP_ISTREAM std::istream +#endif // if JSONCPP_USING_SECURE_MEMORY +} // end namespace Json + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class FastWriter; +class StyledWriter; + +// reader.h +class Reader; + +// features.h +class Features; + +// value.h +typedef unsigned int ArrayIndex; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/features.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_FEATURES_H_INCLUDED +#define CPPTL_JSON_FEATURES_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +#pragma pack(push, 8) + +namespace Json { + +/** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ +class JSON_API Features { +public: + /** \brief A configuration that allows all features and assumes all strings + * are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON + * specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_; + + /// \c true if root must be either an array or an object value. Default: \c + /// false. + bool strictRoot_; + + /// \c true if dropped null placeholders are allowed. Default: \c false. + bool allowDroppedNullPlaceholders_; + + /// \c true if numeric object key are allowed. Default: \c false. + bool allowNumericKeys_; +}; + +} // namespace Json + +#pragma pack(pop) + +#endif // CPPTL_JSON_FEATURES_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/features.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_H_INCLUDED +#define CPPTL_JSON_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include + +#ifndef JSON_USE_CPPTL_SMALLMAP +#include +#else +#include +#endif +#ifdef JSON_USE_CPPTL +#include +#endif + +// Conditional NORETURN attribute on the throw functions would: +// a) suppress false positives from static code analysis +// b) possibly improve optimization opportunities. +#if !defined(JSONCPP_NORETURN) +#if defined(_MSC_VER) +#define JSONCPP_NORETURN __declspec(noreturn) +#elif defined(__GNUC__) +#define JSONCPP_NORETURN __attribute__((__noreturn__)) +#else +#define JSONCPP_NORETURN +#endif +#endif + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + +/** Base class for all exceptions we throw. + * + * We use nothing but these internally. Of course, STL can throw others. + */ +class JSON_API Exception : public std::exception { +public: + Exception(JSONCPP_STRING const& msg); + ~Exception() JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; + char const* what() const JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; + +protected: + JSONCPP_STRING msg_; +}; + +/** Exceptions which the user cannot easily avoid. + * + * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input + * + * \remark derived from Json::Exception + */ +class JSON_API RuntimeError : public Exception { +public: + RuntimeError(JSONCPP_STRING const& msg); +}; + +/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. + * + * These are precondition-violations (user bugs) and internal errors (our bugs). + * + * \remark derived from Json::Exception + */ +class JSON_API LogicError : public Exception { +public: + LogicError(JSONCPP_STRING const& msg); +}; + +/// used internally +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg); +/// used internally +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg); + +/** \brief Type of the value held by a Value object. + */ +enum ValueType { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). +}; + +enum CommentPlacement { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for + /// root value) + numberOfCommentPlacement +}; + +/** \brief Type of precision for formatting of real values. + */ +enum PrecisionType { + significantDigits = 0, ///< we set max number of significant digits in string + decimalPlaces ///< we set max number of digits after "." in string +}; + +//# ifdef JSON_USE_CPPTL +// typedef CppTL::AnyEnumerator EnumMemberNames; +// typedef CppTL::AnyEnumerator EnumValues; +//# endif + +/** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignment takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ +class JSON_API StaticString { +public: + explicit StaticString(const char* czstring) : c_str_(czstring) {} + + operator const char*() const { return c_str_; } + + const char* c_str() const { return c_str_; } + +private: + const char* c_str_; +}; + +/** \brief Represents a JSON value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * Values of an #objectValue or #arrayValue can be accessed using operator[]() + * methods. + * Non-const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resized and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtain default value in the case the + * required element does not exist. + * + * It is possible to iterate over the list of a #objectValue values using + * the getMemberNames() method. + * + * \note #Value string-length fit in size_t, but keys must be < 2^30. + * (The reason is an implementation detail.) A #CharReader will raise an + * exception if a bound is exceeded to avoid security holes in your app, + * but the Value API does *not* check bounds. That is the responsibility + * of the caller. + */ +class JSON_API Value { + friend class ValueIteratorBase; + +public: + typedef std::vector Members; + typedef ValueIterator iterator; + typedef ValueConstIterator const_iterator; + typedef Json::UInt UInt; + typedef Json::Int Int; +#if defined(JSON_HAS_INT64) + typedef Json::UInt64 UInt64; + typedef Json::Int64 Int64; +#endif // defined(JSON_HAS_INT64) + typedef Json::LargestInt LargestInt; + typedef Json::LargestUInt LargestUInt; + typedef Json::ArrayIndex ArrayIndex; + + // Required for boost integration, e. g. BOOST_TEST + typedef std::string value_type; + + static const Value& null; ///< We regret this reference to a global instance; + ///< prefer the simpler Value(). + static const Value& nullRef; ///< just a kludge for binary-compatibility; same + ///< as null + static Value const& nullSingleton(); ///< Prefer this to null or nullRef. + + /// Minimum signed integer value that can be stored in a Json::Value. + static const LargestInt minLargestInt; + /// Maximum signed integer value that can be stored in a Json::Value. + static const LargestInt maxLargestInt; + /// Maximum unsigned integer value that can be stored in a Json::Value. + static const LargestUInt maxLargestUInt; + + /// Minimum signed int value that can be stored in a Json::Value. + static const Int minInt; + /// Maximum signed int value that can be stored in a Json::Value. + static const Int maxInt; + /// Maximum unsigned int value that can be stored in a Json::Value. + static const UInt maxUInt; + +#if defined(JSON_HAS_INT64) + /// Minimum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 minInt64; + /// Maximum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 maxInt64; + /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. + static const UInt64 maxUInt64; +#endif // defined(JSON_HAS_INT64) + + /// Default precision for real value for string representation. + static const UInt defaultRealPrecision; + +// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler +// when using gcc and clang backend compilers. CZString +// cannot be defined as private. See issue #486 +#ifdef __NVCC__ +public: +#else +private: +#endif +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + class CZString { + public: + enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy }; + CZString(ArrayIndex index); + CZString(char const* str, unsigned length, DuplicationPolicy allocate); + CZString(CZString const& other); +#if JSON_HAS_RVALUE_REFERENCES + CZString(CZString&& other); +#endif + ~CZString(); + CZString& operator=(const CZString& other); + +#if JSON_HAS_RVALUE_REFERENCES + CZString& operator=(CZString&& other); +#endif + + bool operator<(CZString const& other) const; + bool operator==(CZString const& other) const; + ArrayIndex index() const; + // const char* c_str() const; ///< \deprecated + char const* data() const; + unsigned length() const; + bool isStaticString() const; + + private: + void swap(CZString& other); + + struct StringStorage { + unsigned policy_ : 2; + unsigned length_ : 30; // 1GB max + }; + + char const* cstr_; // actually, a prefixed string, unless policy is noDup + union { + ArrayIndex index_; + StringStorage storage_; + }; + }; + +public: +#ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map ObjectValues; +#else + typedef CppTL::SmallMap ObjectValues; +#endif // ifndef JSON_USE_CPPTL_SMALLMAP +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + +public: + /** \brief Create a default Value of the given type. + + This is a very useful constructor. + To create an empty array, pass arrayValue. + To create an empty object, pass objectValue. + Another Value can then be set to this one by assignment. +This is useful since clear() and resize() will not alter types. + + Examples: +\code +Json::Value null_value; // null +Json::Value arr_value(Json::arrayValue); // [] +Json::Value obj_value(Json::objectValue); // {} +\endcode + */ + Value(ValueType type = nullValue); + Value(Int value); + Value(UInt value); +#if defined(JSON_HAS_INT64) + Value(Int64 value); + Value(UInt64 value); +#endif // if defined(JSON_HAS_INT64) + Value(double value); + Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) + Value(const char* begin, const char* end); ///< Copy all, incl zeroes. + /** \brief Constructs a value from a static string. + + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to this + * constructor. + * \note This works only for null-terminated strings. (We cannot change the + * size of this class, so we have nowhere to store the length, + * which might be computed later for various operations.) + * + * Example of usage: + * \code + * static StaticString foo("some text"); + * Json::Value aValue(foo); + * \endcode + */ + Value(const StaticString& value); + Value(const JSONCPP_STRING& value); ///< Copy data() til size(). Embedded + ///< zeroes too. +#ifdef JSON_USE_CPPTL + Value(const CppTL::ConstString& value); +#endif + Value(bool value); + /// Deep copy. + Value(const Value& other); +#if JSON_HAS_RVALUE_REFERENCES + /// Move constructor + Value(Value&& other); +#endif + ~Value(); + + /// Deep copy, then swap(other). + /// \note Over-write existing comments. To preserve comments, use + /// #swapPayload(). + Value& operator=(Value other); + + /// Swap everything. + void swap(Value& other); + /// Swap values but leave comments and source offsets in place. + void swapPayload(Value& other); + + /// copy everything. + void copy(const Value& other); + /// copy values but leave comments and source offsets in place. + void copyPayload(const Value& other); + + ValueType type() const; + + /// Compare payload only, not comments etc. + bool operator<(const Value& other) const; + bool operator<=(const Value& other) const; + bool operator>=(const Value& other) const; + bool operator>(const Value& other) const; + bool operator==(const Value& other) const; + bool operator!=(const Value& other) const; + int compare(const Value& other) const; + + const char* asCString() const; ///< Embedded zeroes could cause you trouble! +#if JSONCPP_USING_SECURE_MEMORY + unsigned getCStringLength() const; // Allows you to understand the length of + // the CString +#endif + JSONCPP_STRING asString() const; ///< Embedded zeroes are possible. + /** Get raw char* of string-value. + * \return false if !string. (Seg-fault if str or end are NULL.) + */ + bool getString(char const** begin, char const** end) const; +#ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +#endif + Int asInt() const; + UInt asUInt() const; +#if defined(JSON_HAS_INT64) + Int64 asInt64() const; + UInt64 asUInt64() const; +#endif // if defined(JSON_HAS_INT64) + LargestInt asLargestInt() const; + LargestUInt asLargestUInt() const; + float asFloat() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isInt64() const; + bool isUInt() const; + bool isUInt64() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + bool isConvertibleTo(ValueType other) const; + + /// Number of values in array or object + ArrayIndex size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return !isNull() + JSONCPP_OP_EXPLICIT operator bool() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to newSize elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize(ArrayIndex newSize); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are + /// inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](ArrayIndex index); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are + /// inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](int index); + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](ArrayIndex index) const; + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](int index) const; + + /// If the array contains at least index+1 elements, returns the element + /// value, + /// otherwise returns defaultValue. + Value get(ArrayIndex index, const Value& defaultValue) const; + /// Return true if index < size(). + bool isValidIndex(ArrayIndex index) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value& append(const Value& value); + +#if JSON_HAS_RVALUE_REFERENCES + Value& append(Value&& value); +#endif + + /// Access an object value by name, create a null member if it does not exist. + /// \note Because of our implementation, keys are limited to 2^30 -1 chars. + /// Exceeding that will cause an exception. + Value& operator[](const char* key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const char* key) const; + /// Access an object value by name, create a null member if it does not exist. + /// \param key may contain embedded nulls. + Value& operator[](const JSONCPP_STRING& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + /// \param key may contain embedded nulls. + const Value& operator[](const JSONCPP_STRING& key) const; + /** \brief Access an object value by name, create a null member if it does not + exist. + + * If the object has no entry for that name, then the member name used to + store + * the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value& operator[](const StaticString& key); +#ifdef JSON_USE_CPPTL + /// Access an object value by name, create a null member if it does not exist. + Value& operator[](const CppTL::ConstString& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const CppTL::ConstString& key) const; +#endif + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const char* key, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \note key may contain embedded nulls. + Value + get(const char* begin, const char* end, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \param key may contain embedded nulls. + Value get(const JSONCPP_STRING& key, const Value& defaultValue) const; +#ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const CppTL::ConstString& key, const Value& defaultValue) const; +#endif + /// Most general and efficient version of isMember()const, get()const, + /// and operator[]const + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + Value const* find(char const* begin, char const* end) const; + /// Most general and efficient version of object-mutators. + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. + Value const* demand(char const* begin, char const* end); + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \return the removed Value, or null. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + /// \deprecated + void removeMember(const char* key); + /// Same as removeMember(const char*) + /// \param key may contain embedded nulls. + /// \deprecated + void removeMember(const JSONCPP_STRING& key); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); + /** \brief Remove the named map member. + + Update 'removed' iff removed. + \param key may contain embedded nulls. + \return true iff removed (no exceptions) + */ + bool removeMember(JSONCPP_STRING const& key, Value* removed); + /// Same as removeMember(JSONCPP_STRING const& key, Value* removed) + bool removeMember(const char* begin, const char* end, Value* removed); + /** \brief Remove the indexed array element. + + O(n) expensive operations. + Update 'removed' iff removed. + \return true if removed (no exceptions) + */ + bool removeIndex(ArrayIndex index, Value* removed); + + /// Return true if the object has a member named key. + /// \note 'key' must be null-terminated. + bool isMember(const char* key) const; + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. + bool isMember(const JSONCPP_STRING& key) const; + /// Same as isMember(JSONCPP_STRING const& key)const + bool isMember(const char* begin, const char* end) const; +#ifdef JSON_USE_CPPTL + /// Return true if the object has a member named key. + bool isMember(const CppTL::ConstString& key) const; +#endif + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + + //# ifdef JSON_USE_CPPTL + // EnumMemberNames enumMemberNames() const; + // EnumValues enumValues() const; + //# endif + + /// \deprecated Always pass len. + JSONCPP_DEPRECATED("Use setComment(JSONCPP_STRING const&) instead.") + void setComment(const char* comment, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const char* comment, size_t len, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const JSONCPP_STRING& comment, CommentPlacement placement); + bool hasComment(CommentPlacement placement) const; + /// Include delimiters and embedded newlines. + JSONCPP_STRING getComment(CommentPlacement placement) const; + + JSONCPP_STRING toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + // Accessors for the [start, limit) range of bytes within the JSON text from + // which this value was parsed, if any. + void setOffsetStart(ptrdiff_t start); + void setOffsetLimit(ptrdiff_t limit); + ptrdiff_t getOffsetStart() const; + ptrdiff_t getOffsetLimit() const; + +private: + void initBasic(ValueType type, bool allocated = false); + void dupPayload(const Value& other); + void releasePayload(); + void dupMeta(const Value& other); + + Value& resolveReference(const char* key); + Value& resolveReference(const char* key, const char* end); + + struct CommentInfo { + CommentInfo(); + ~CommentInfo(); + + void setComment(const char* text, size_t len); + + char* comment_; + }; + + // struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder { + LargestInt int_; + LargestUInt uint_; + double real_; + bool bool_; + char* string_; // actually ptr to unsigned, followed by str, unless + // !allocated_ + ObjectValues* map_; + } value_; + ValueType type_ : 8; + unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is + // useless. If not allocated_, string_ must be + // null-terminated. + CommentInfo* comments_; + + // [start, limit) byte offsets in the source JSON text from which this Value + // was extracted. + ptrdiff_t start_; + ptrdiff_t limit_; +}; + +/** \brief Experimental and untested: represents an element of the "path" to + * access a node. + */ +class JSON_API PathArgument { +public: + friend class Path; + + PathArgument(); + PathArgument(ArrayIndex index); + PathArgument(const char* key); + PathArgument(const JSONCPP_STRING& key); + +private: + enum Kind { kindNone = 0, kindIndex, kindKey }; + JSONCPP_STRING key_; + ArrayIndex index_; + Kind kind_; +}; + +/** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provied as parameter + */ +class JSON_API Path { +public: + Path(const JSONCPP_STRING& path, + const PathArgument& a1 = PathArgument(), + const PathArgument& a2 = PathArgument(), + const PathArgument& a3 = PathArgument(), + const PathArgument& a4 = PathArgument(), + const PathArgument& a5 = PathArgument()); + + const Value& resolve(const Value& root) const; + Value resolve(const Value& root, const Value& defaultValue) const; + /// Creates the "path" to access the specified node and returns a reference on + /// the node. + Value& make(Value& root) const; + +private: + typedef std::vector InArgs; + typedef std::vector Args; + + void makePath(const JSONCPP_STRING& path, const InArgs& in); + void addPathInArg(const JSONCPP_STRING& path, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind); + static void invalidPath(const JSONCPP_STRING& path, int location); + + Args args_; +}; + +/** \brief base class for Value iterators. + * + */ +class JSON_API ValueIteratorBase { +public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + bool operator==(const SelfType& other) const { return isEqual(other); } + + bool operator!=(const SelfType& other) const { return !isEqual(other); } + + difference_type operator-(const SelfType& other) const { + return other.computeDistance(*this); + } + + /// Return either the index or the member name of the referenced value as a + /// Value. + Value key() const; + + /// Return the index of the referenced Value, or -1 if it is not an + /// arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value, or "" if it is not an + /// objectValue. + /// \note Avoid `c_str()` on result, as embedded zeroes are possible. + JSONCPP_STRING name() const; + + /// Return the member name of the referenced Value. "" if it is not an + /// objectValue. + /// \deprecated This cannot be used for UTF-8 strings, since there can be + /// embedded nulls. + JSONCPP_DEPRECATED("Use `key = name();` instead.") + char const* memberName() const; + /// Return the member name of the referenced Value, or NULL if it is not an + /// objectValue. + /// \note Better version than memberName(). Allows embedded nulls. + char const* memberName(char const** end) const; + +protected: + Value& deref() const; + + void increment(); + + void decrement(); + + difference_type computeDistance(const SelfType& other) const; + + bool isEqual(const SelfType& other) const; + + void copy(const SelfType& other); + +private: + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; + +public: + // For some reason, BORLAND needs these at the end, rather + // than earlier. No idea why. + ValueIteratorBase(); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); +}; + +/** \brief const iterator for object and array value. + * + */ +class JSON_API ValueConstIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef const Value value_type; + // typedef unsigned int size_t; + // typedef int difference_type; + typedef const Value& reference; + typedef const Value* pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); + ValueConstIterator(ValueIterator const& other); + +private: + /*! \internal Use by Value to create an iterator. + */ + explicit ValueConstIterator(const Value::ObjectValues::iterator& current); + +public: + SelfType& operator=(const ValueIteratorBase& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +/** \brief Iterator for object and array value. + */ +class JSON_API ValueIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef Value value_type; + typedef unsigned int size_t; + typedef int difference_type; + typedef Value& reference; + typedef Value* pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + explicit ValueIterator(const ValueConstIterator& other); + ValueIterator(const ValueIterator& other); + +private: + /*! \internal Use by Value to create an iterator. + */ + explicit ValueIterator(const Value::ObjectValues::iterator& current); + +public: + SelfType& operator=(const SelfType& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +inline void swap(Value& a, Value& b) { a.swap(b); } + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_READER_H_INCLUDED +#define CPPTL_JSON_READER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "features.h" +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +namespace Json { + +/** \brief Unserialize a JSON document into a + *Value. + * + * \deprecated Use CharReader and CharReaderBuilder. + */ +class JSON_API Reader { +public: + typedef char Char; + typedef const Char* Location; + + /** \brief An error tagged with where in the JSON text it was encountered. + * + * The offsets give the [start, limit) range of bytes within the text. Note + * that this is bytes, not codepoints. + * + */ + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; + }; + + /** \brief Constructs a Reader allowing all features + * for parsing. + */ + JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set + * for parsing. + */ + JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") + Reader(const Features& features); + + /** \brief Read a Value from a JSON + * document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them + * back during + * serialization, \c false to discard comments. + * This parameter is ignored if + * Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + bool + parse(const std::string& document, Value& root, bool collectComments = true); + + /** \brief Read a Value from a JSON + document. + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the + document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + document to read. + * Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them + back during + * serialization, \c false to discard comments. + * This parameter is ignored if + Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse(JSONCPP_ISTREAM& is, Value& root, bool collectComments = true); + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * \return Formatted error message with the list of errors with their location + * in + * the parsed document. An empty string is returned if no error + * occurred + * during parsing. + * \deprecated Use getFormattedErrorMessages() instead (typo fix). + */ + JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") + JSONCPP_STRING getFormatedErrorMessages() const; + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * \return Formatted error message with the list of errors with their location + * in + * the parsed document. An empty string is returned if no error + * occurred + * during parsing. + */ + JSONCPP_STRING getFormattedErrorMessages() const; + + /** \brief Returns a vector of structured erros encounted while parsing. + * \return A (possibly empty) vector of StructuredError objects. Currently + * only one error can be returned, but the caller should tolerate + * multiple + * errors. This can occur if the parser recovers from a non-fatal + * parse error and then encounters additional errors. + */ + std::vector getStructuredErrors() const; + + /** \brief Add a semantic error message. + * \param value JSON Value location associated with the error + * \param message The error message. + * \return \c true if the error was successfully added, \c false if the + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const JSONCPP_STRING& message); + + /** \brief Add a semantic error message with extra context. + * \param value JSON Value location associated with the error + * \param message The error message. + * \param extra Additional JSON Value location to contextualize the error + * \return \c true if the error was successfully added, \c false if either + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, + const JSONCPP_STRING& message, + const Value& extra); + + /** \brief Return whether there are any errors. + * \return \c true if there are no errors to report \c false if + * errors have occurred. + */ + bool good() const; + +private: + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + JSONCPP_STRING message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, JSONCPP_STRING& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool + addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + JSONCPP_STRING getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + static bool containsNewLine(Location begin, Location end); + static JSONCPP_STRING normalizeEOL(Location begin, Location end); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + JSONCPP_STRING document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + JSONCPP_STRING commentsBefore_; + Features features_; + bool collectComments_; +}; // Reader + +/** Interface for reading JSON from a char array. + */ +class JSON_API CharReader { +public: + virtual ~CharReader() {} + /** \brief Read a Value from a JSON + document. + * The document must be a UTF-8 encoded string containing the document to + read. + * + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the + document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + document to read. + * Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param errs [out] Formatted error messages (if not NULL) + * a user friendly string that lists errors in the parsed + * document. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + virtual bool parse(char const* beginDoc, + char const* endDoc, + Value* root, + JSONCPP_STRING* errs) = 0; + + class JSON_API Factory { + public: + virtual ~Factory() {} + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual CharReader* newCharReader() const = 0; + }; // Factory +}; // CharReader + +/** \brief Build a CharReader implementation. + +Usage: +\code + using namespace Json; + CharReaderBuilder builder; + builder["collectComments"] = false; + Value value; + JSONCPP_STRING errs; + bool ok = parseFromStream(builder, std::cin, &value, &errs); +\endcode +*/ +class JSON_API CharReaderBuilder : public CharReader::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + These are case-sensitive. + Available settings (case-sensitive): + - `"collectComments": false or true` + - true to collect comment and allow writing them + back during serialization, false to discard comments. + This parameter is ignored if allowComments is false. + - `"allowComments": false or true` + - true if comments are allowed. + - `"strictRoot": false or true` + - true if root must be either an array or an object value + - `"allowDroppedNullPlaceholders": false or true` + - true if dropped null placeholders are allowed. (See + StreamWriterBuilder.) + - `"allowNumericKeys": false or true` + - true if numeric object keys are allowed. + - `"allowSingleQuotes": false or true` + - true if '' are allowed for strings (both keys and values) + - `"stackLimit": integer` + - Exceeding stackLimit (recursive depth of `readValue()`) will + cause an exception. + - This is a security issue (seg-faults caused by deeply nested JSON), + so the default is low. + - `"failIfExtra": false or true` + - If true, `parse()` returns false when extra non-whitespace trails + the JSON value in the input string. + - `"rejectDupKeys": false or true` + - If true, `parse()` returns false when a key is duplicated within an + object. + - `"allowSpecialFloats": false or true` + - If true, special float values (NaNs and infinities) are allowed + and their values are lossfree restorable. + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + CharReaderBuilder(); + ~CharReaderBuilder() JSONCPP_OVERRIDE; + + CharReader* newCharReader() const JSONCPP_OVERRIDE; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + + /** A simple way to update a specific setting. + */ + Value& operator[](JSONCPP_STRING key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults + */ + static void setDefaults(Json::Value* settings); + /** Same as old Features::strictMode(). + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode + */ + static void strictMode(Json::Value* settings); +}; + +/** Consume entire stream and use its begin/end. + * Someday we might have a real StreamReader, but for now this + * is convenient. + */ +bool JSON_API parseFromStream(CharReader::Factory const&, + JSONCPP_ISTREAM&, + Value* root, + std::string* errs); + +/** \brief Read from 'sin' into 'root'. + + Always keep comments from the input JSON. + + This can be used to read a file into a particular sub-object. + For example: + \code + Json::Value root; + cin >> root["dir"]["file"]; + cout << root; + \endcode + Result: + \verbatim + { + "dir": { + "file": { + // The input stream JSON would be nested here. + } + } + } + \endverbatim + \throw std::exception on parse error. + \see Json::operator<<() +*/ +JSON_API JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM&, Value&); + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_READER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_WRITER_H_INCLUDED +#define JSON_WRITER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) && defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +namespace Json { + +class Value; + +/** + +Usage: +\code + using namespace Json; + void writeToStdout(StreamWriter::Factory const& factory, Value const& value) { + std::unique_ptr const writer( + factory.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush + } +\endcode +*/ +class JSON_API StreamWriter { +protected: + JSONCPP_OSTREAM* sout_; // not owned; will not delete +public: + StreamWriter(); + virtual ~StreamWriter(); + /** Write Value into document as configured in sub-class. + Do not take ownership of sout, but maintain a reference during function. + \pre sout != NULL + \return zero on success (For now, we always return zero, so check the + stream instead.) \throw std::exception possibly, depending on configuration + */ + virtual int write(Value const& root, JSONCPP_OSTREAM* sout) = 0; + + /** \brief A simple abstract factory. + */ + class JSON_API Factory { + public: + virtual ~Factory(); + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual StreamWriter* newStreamWriter() const = 0; + }; // Factory +}; // StreamWriter + +/** \brief Write into stringstream, then return string, for convenience. + * A StreamWriter will be created from the factory, used, and then deleted. + */ +JSONCPP_STRING JSON_API writeString(StreamWriter::Factory const& factory, + Value const& root); + +/** \brief Build a StreamWriter implementation. + +Usage: +\code + using namespace Json; + Value value = ...; + StreamWriterBuilder builder; + builder["commentStyle"] = "None"; + builder["indentation"] = " "; // or whatever you like + std::unique_ptr writer( + builder.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush +\endcode +*/ +class JSON_API StreamWriterBuilder : public StreamWriter::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + Available settings (case-sensitive): + - "commentStyle": "None" or "All" + - "indentation": "". + - Setting this to an empty string also omits newline characters. + - "enableYAMLCompatibility": false or true + - slightly change the whitespace around colons + - "dropNullPlaceholders": false or true + - Drop the "null" string from the writer's output for nullValues. + Strictly speaking, this is not valid JSON. But when the output is being + fed to a browser's JavaScript, it makes for smaller output and the + browser can handle the output just fine. + - "useSpecialFloats": false or true + - If true, outputs non-finite floating point values in the following way: + NaN values as "NaN", positive infinity as "Infinity", and negative + infinity as "-Infinity". + - "precision": int + - Number of precision digits for formatting of real values. + - "precisionType": "significant"(default) or "decimal" + - Type of precision for formatting of real values. + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + StreamWriterBuilder(); + ~StreamWriterBuilder() JSONCPP_OVERRIDE; + + /** + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + /** A simple way to update a specific setting. + */ + Value& operator[](JSONCPP_STRING key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults + */ + static void setDefaults(Json::Value* settings); +}; + +/** \brief Abstract class for writers. + * \deprecated Use StreamWriter. (And really, this is an implementation detail.) + */ +class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer { +public: + virtual ~Writer(); + + virtual JSONCPP_STRING write(const Value& root) = 0; +}; + +/** \brief Outputs a Value in JSON format + *without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' + *consumption, + * but may be useful to support feature such as RPC where bandwidth is limited. + * \sa Reader, Value + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter + : public Writer { +public: + FastWriter(); + ~FastWriter() JSONCPP_OVERRIDE {} + + void enableYAMLCompatibility(); + + /** \brief Drop the "null" string from the writer's output for nullValues. + * Strictly speaking, this is not valid JSON. But when the output is being + * fed to a browser's JavaScript, it makes for smaller output and the + * browser can handle the output just fine. + */ + void dropNullPlaceholders(); + + void omitEndingLineFeed(); + +public: // overridden from Writer + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; + +private: + void writeValue(const Value& value); + + JSONCPP_STRING document_; + bool yamlCompatibilityEnabled_; + bool dropNullPlaceholders_; + bool omitEndingLineFeed_; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +/** \brief Writes a Value in JSON format in a + *human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + *line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + *types, + * and all the values fit on one lines, then print the array on a single + *line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + *#CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API + StyledWriter : public Writer { +public: + StyledWriter(); + ~StyledWriter() JSONCPP_OVERRIDE {} + +public: // overridden from Writer + /** \brief Serialize a Value in JSON format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultilineArray(const Value& value); + void pushValue(const JSONCPP_STRING& value); + void writeIndent(); + void writeWithIndent(const JSONCPP_STRING& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + static bool hasCommentForValue(const Value& value); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + JSONCPP_STRING document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + unsigned int indentSize_; + bool addChildValues_; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +/** \brief Writes a Value in JSON format in a + human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + types, + * and all the values fit on one lines, then print the array on a single + line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + #CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API + StyledStreamWriter { +public: + /** + * \param indentation Each level will be indented by this amount extra. + */ + StyledStreamWriter(const JSONCPP_STRING& indentation = "\t"); + ~StyledStreamWriter() {} + +public: + /** \brief Serialize a Value in JSON format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not + * return a value. + */ + void write(JSONCPP_OSTREAM& out, const Value& root); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultilineArray(const Value& value); + void pushValue(const JSONCPP_STRING& value); + void writeIndent(); + void writeWithIndent(const JSONCPP_STRING& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + static bool hasCommentForValue(const Value& value); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + JSONCPP_OSTREAM* document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; + bool addChildValues_ : 1; + bool indented_ : 1; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(JSON_HAS_INT64) +JSONCPP_STRING JSON_API valueToString(Int value); +JSONCPP_STRING JSON_API valueToString(UInt value); +#endif // if defined(JSON_HAS_INT64) +JSONCPP_STRING JSON_API valueToString(LargestInt value); +JSONCPP_STRING JSON_API valueToString(LargestUInt value); +JSONCPP_STRING JSON_API +valueToString(double value, + unsigned int precision = Value::defaultRealPrecision, + PrecisionType precisionType = PrecisionType::significantDigits); +JSONCPP_STRING JSON_API valueToString(bool value); +JSONCPP_STRING JSON_API valueToQuotedString(const char* value); + +/// \brief Output using the StyledStreamWriter. +/// \see Json::operator>>() +JSON_API JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM&, const Value& root); + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_WRITER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/assertions.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED +#define CPPTL_JSON_ASSERTIONS_H_INCLUDED + +#include +#include + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +/** It should not be possible for a maliciously designed file to + * cause an abort() or seg-fault, so these macros are used only + * for pre-condition violations and internal logic errors. + */ +#if JSON_USE_EXCEPTION + +// @todo <= add detail about condition in exception +#define JSON_ASSERT(condition) \ + { \ + if (!(condition)) { \ + Json::throwLogicError("assert json failed"); \ + } \ + } + +#define JSON_FAIL_MESSAGE(message) \ + { \ + JSONCPP_OSTRINGSTREAM oss; \ + oss << message; \ + Json::throwLogicError(oss.str()); \ + abort(); \ + } + +#else // JSON_USE_EXCEPTION + +#define JSON_ASSERT(condition) assert(condition) + +// The call to assert() will show the failure message in debug builds. In +// release builds we abort, for a core-dump or debugger. +#define JSON_FAIL_MESSAGE(message) \ + { \ + JSONCPP_OSTRINGSTREAM oss; \ + oss << message; \ + assert(false && oss.str().c_str()); \ + abort(); \ + } + +#endif + +#define JSON_ASSERT_MESSAGE(condition, message) \ + if (!(condition)) { \ + JSON_FAIL_MESSAGE(message); \ + } + +#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/assertions.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_AMALGAMATED_H_INCLUDED diff --git a/example/jsoncpp.cpp b/example/jsoncpp.cpp new file mode 100644 index 0000000..ebd3aa5 --- /dev/null +++ b/example/jsoncpp.cpp @@ -0,0 +1,5467 @@ +/// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + + +#include "json/json.h" +#ifndef JSON_IS_AMALGAMATION +#error "Compile with -I PATH_TO_JSON_DIRECTORY" +#endif + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_tool.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED +#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include +#endif + +// Also support old flag NO_LOCALE_SUPPORT +#ifdef NO_LOCALE_SUPPORT +#define JSONCPP_NO_LOCALE_SUPPORT +#endif + +#ifndef JSONCPP_NO_LOCALE_SUPPORT +#include +#endif + +/* This header provides common string manipulation support, such as UTF-8, + * portable conversion from/to string... + * + * It is an internal header that must not be exposed. + */ + +namespace Json { +static inline char getDecimalPoint() { +#ifdef JSONCPP_NO_LOCALE_SUPPORT + return '\0'; +#else + struct lconv* lc = localeconv(); + return lc ? *(lc->decimal_point) : '\0'; +#endif +} + +/// Converts a unicode code-point to UTF-8. +static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) { + JSONCPP_STRING result; + + // based on description from http://en.wikipedia.org/wiki/UTF-8 + + if (cp <= 0x7f) { + result.resize(1); + result[0] = static_cast(cp); + } else if (cp <= 0x7FF) { + result.resize(2); + result[1] = static_cast(0x80 | (0x3f & cp)); + result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); + } else if (cp <= 0xFFFF) { + result.resize(3); + result[2] = static_cast(0x80 | (0x3f & cp)); + result[1] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[0] = static_cast(0xE0 | (0xf & (cp >> 12))); + } else if (cp <= 0x10FFFF) { + result.resize(4); + result[3] = static_cast(0x80 | (0x3f & cp)); + result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); + } + // printf("-----------------111--cp %d-------\n",cp); + if ((cp >= 0x4E00 && cp <= 0x9FA5) || (cp >= 0xF00 && cp <= 0xFA2D) ) + { + + wchar_t src[2] = { 0 }; + char dest[5] = { 0 }; + src[0] = static_cast(cp); + std::string curLocale = setlocale(LC_ALL,NULL); + setlocale(LC_ALL,"chs"); + wcstombs(dest, src, 5); + result = dest; + setlocale(LC_ALL, curLocale.c_str()); + } + + + return result; +} + +enum { + /// Constant that specify the size of the buffer that must be passed to + /// uintToString. + uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 +}; + +// Defines a char buffer for use with uintToString(). +typedef char UIntToStringBuffer[uintToStringBufferSize]; + +/** Converts an unsigned integer to string. + * @param value Unsigned integer to convert to string + * @param current Input/Output string buffer. + * Must have at least uintToStringBufferSize chars free. + */ +static inline void uintToString(LargestUInt value, char*& current) { + *--current = 0; + do { + *--current = static_cast(value % 10U + static_cast('0')); + value /= 10; + } while (value != 0); +} + +/** Change ',' to '.' everywhere in buffer. + * + * We had a sophisticated way, but it did not work in WinCE. + * @see https://github.com/open-source-parsers/jsoncpp/pull/9 + */ +template Iter fixNumericLocale(Iter begin, Iter end) { + for (; begin != end; ++begin) { + if (*begin == ',') { + *begin = '.'; + } + } + return begin; +} + +template void fixNumericLocaleInput(Iter begin, Iter end) { + char decimalPoint = getDecimalPoint(); + if (decimalPoint == '\0' || decimalPoint == '.') { + return; + } + for (; begin != end; ++begin) { + if (*begin == '.') { + *begin = decimalPoint; + } + } +} + +/** + * Return iterator that would be the new end of the range [begin,end), if we + * were to delete zeros in the end of string, but not the last zero before '.'. + */ +template Iter fixZerosInTheEnd(Iter begin, Iter end) { + for (; begin != end; --end) { + if (*(end - 1) != '0') { + return end; + } + // Don't delete the last zero before the decimal point. + if (begin != (end - 1) && *(end - 2) == '.') { + return end; + } + } + return end; +} + +} // namespace Json + +#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_tool.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors +// Copyright (C) 2016 InfoTeCS JSC. All rights reserved. +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include "json_tool.h" +#include +#include +#include +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include +#include +#include + +#if __cplusplus >= 201103L +#include + +#if !defined(snprintf) +#define snprintf std::snprintf +#endif + +#if !defined(sscanf) +#define sscanf std::sscanf +#endif +#else +#include + +#if defined(_MSC_VER) +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 +#if !defined(snprintf) +#define snprintf _snprintf +#endif +#endif +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile +// time to change the stack limit +#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) +#define JSONCPP_DEPRECATED_STACK_LIMIT 1000 +#endif + +static size_t const stackLimit_g = + JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue() + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr CharReaderPtr; +#else +typedef std::auto_ptr CharReaderPtr; +#endif + +// Implementation of class Features +// //////////////////////////////// + +Features::Features() + : allowComments_(true), strictRoot_(false), + allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} + +Features Features::all() { return Features(); } + +Features Features::strictMode() { + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + features.allowDroppedNullPlaceholders_ = false; + features.allowNumericKeys_ = false; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + +bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) { + for (; begin < end; ++begin) + if (*begin == '\n' || *begin == '\r') + return true; + return false; +} + +// Class Reader +// ////////////////////////////////////////////////////////////////// + +Reader::Reader() + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(Features::all()), + collectComments_() {} + +Reader::Reader(const Features& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(features), collectComments_() { +} + +bool Reader::parse(const std::string& document, + Value& root, + bool collectComments) { + document_.assign(document.begin(), document.end()); + const char* begin = document_.c_str(); + const char* end = begin + document_.length(); + return parse(begin, end, root, collectComments); +} + +bool Reader::parse(std::istream& is, Value& root, bool collectComments) { + // std::istream_iterator begin(is); + // std::istream_iterator end; + // Those would allow streamed input from a file, if parse() were a + // template function. + + // Since JSONCPP_STRING is reference-counted, this at least does not + // create an extra copy. + JSONCPP_STRING doc; + std::getline(is, doc, (char)EOF); + return parse(doc.data(), doc.data() + doc.size(), root, collectComments); +} + +bool Reader::parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments) { + if (!features_.allowComments_) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_.clear(); + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) { + if (!root.isArray() && !root.isObject()) { + // Set error location to start of doc, ideally should be first token found + // in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( + "A valid JSON document must be either an array or an object value.", + token); + return false; + } + } + return successful; +} + +bool Reader::readValue() { + // readValue() may call itself only if it calls readObject() or ReadArray(). + // These methods execute nodes_.push() just before and nodes_.pop)() just + // after calling readValue(). parse() executes one nodes_.push(), so > instead + // of >=. + if (nodes_.size() > stackLimit_g) + throwRuntimeError("Exceeded stackLimit in readValue()."); + + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_.clear(); + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenFalse: { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenNull: { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // Else, fall through... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + return successful; +} + +void Reader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool Reader::readToken(Token& token) { + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + token.type_ = tokenNumber; + readNumber(); + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + +void Reader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool Reader::match(Location pattern, int patternLength) { + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool Reader::readComment() { + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if (c == '*') + successful = readCStyleComment(); + else if (c == '/') + successful = readCppStyleComment(); + if (!successful) + return false; + + if (collectComments_) { + CommentPlacement placement = commentBefore; + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (c != '*' || !containsNewLine(commentBegin, current_)) + placement = commentAfterOnSameLine; + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin, + Reader::Location end) { + JSONCPP_STRING normalized; + normalized.reserve(static_cast(end - begin)); + Reader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void Reader::addComment(Location begin, + Location end, + CommentPlacement placement) { + assert(collectComments_); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool Reader::readCStyleComment() { + while ((current_ + 1) < end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool Reader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +void Reader::readNumber() { + const char* p = current_; + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : '\0'; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } +} + +bool Reader::readString() { + Char c = '\0'; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + +bool Reader::readObject(Token& token) { + Token tokenName; + JSONCPP_STRING name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(token.start_ - begin_); + while (readToken(tokenName)) { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + return true; + name.clear(); + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = JSONCPP_STRING(numberName.asCString()); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover("Missing ':' after object member name", colon, + tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment)) { + return addErrorAndRecover("Missing ',' or '}' in object declaration", + comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover("Missing '}' or object member name", tokenName, + tokenObjectEnd); +} + +bool Reader::readArray(Token& token) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(token.start_ - begin_); + skipSpaces(); + if (current_ != end_ && *current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } + int index = 0; + for (;;) { + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token currentToken; + // Accept Comment after last item in the array. + ok = readToken(currentToken); + while (currentToken.type_ == tokenComment && ok) { + ok = readToken(currentToken); + } + bool badTokenType = (currentToken.type_ != tokenArraySeparator && + currentToken.type_ != tokenArrayEnd); + if (!ok || badTokenType) { + return addErrorAndRecover("Missing ',' or ']' in array declaration", + currentToken, tokenArrayEnd); + } + if (currentToken.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool Reader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeNumber(Token& token, Value& decoded) { + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if (isNegative) + ++current; + // TODO: Help the compiler do the div and mod at compile time or get rid of + // them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(static_cast(c - '0')); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative && value == maxIntegerValue) + decoded = Value::minLargestInt; + else if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool Reader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + JSONCPP_STRING buffer(token.start_, token.end_); + JSONCPP_ISTRINGSTREAM is(buffer); + if (!(is >> value)) + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool Reader::decodeString(Token& token) { + JSONCPP_STRING decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) { + decoded.reserve(static_cast(token.end_ - token.start_ - 2)); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + + //printf("-->>>>>>>>>>>>>>>>>>>1>>>>>>\n"); + + while (current != end) { + Char c = *current++; + if (c == '"') + break; + else if (c == '\\') { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } break; + default: + return addError("Bad escape sequence in string", token, current); + } + } else { + decoded += c; + } + } + return true; +} + +bool Reader::decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) + return addError( + "additional six characters expected to parse unicode surrogate pair.", + token, current); + if (*(current++) == '\\' && *(current++) == 'u') { + unsigned int surrogatePair; + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } else + return false; + } else + return addError("expecting another \\u token to begin the second half of " + "a unicode surrogate pair", + token, current); + } + return true; +} + +bool Reader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& ret_unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", token, + current); + int unicode = 0; + for (int index = 0; index < 4; ++index) { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError( + "Bad unicode escape sequence in string: hexadecimal digit expected.", + token, current); + } + ret_unicode = static_cast(unicode); + return true; +} + +bool Reader::addError(const JSONCPP_STRING& message, + Token& token, + Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool Reader::recoverFromError(TokenType skipUntilToken) { + size_t const errorCount = errors_.size(); + Token skip; + for (;;) { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} + +bool Reader::addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& Reader::currentValue() { return *(nodes_.top()); } + +Reader::Char Reader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void Reader::getLocationLineAndColumn(Location location, + int& line, + int& column) const { + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) { + Char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + +JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +// Deprecated. Preserved for backward compatibility +JSONCPP_STRING Reader::getFormatedErrorMessages() const { + return getFormattedErrorMessages(); +} + +JSONCPP_STRING Reader::getFormattedErrorMessages() const { + JSONCPP_STRING formattedMessage; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); ++itError) { + const ErrorInfo& error = *itError; + formattedMessage += + "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += + "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} + +std::vector Reader::getStructuredErrors() const { + std::vector allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); ++itError) { + const ErrorInfo& error = *itError; + Reader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) { + ptrdiff_t const length = end_ - begin_; + if (value.getOffsetStart() > length || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool Reader::pushError(const Value& value, + const JSONCPP_STRING& message, + const Value& extra) { + ptrdiff_t const length = end_ - begin_; + if (value.getOffsetStart() > length || value.getOffsetLimit() > length || + extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool Reader::good() const { return !errors_.size(); } + +// exact copy of Features +class OurFeatures { +public: + static OurFeatures all(); + bool allowComments_; + bool strictRoot_; + bool allowDroppedNullPlaceholders_; + bool allowNumericKeys_; + bool allowSingleQuotes_; + bool failIfExtra_; + bool rejectDupKeys_; + bool allowSpecialFloats_; + int stackLimit_; +}; // OurFeatures + +// exact copy of Implementation of class Features +// //////////////////////////////// + +OurFeatures OurFeatures::all() { return OurFeatures(); } + +// Implementation of class Reader +// //////////////////////////////// + +// exact copy of Reader, renamed to OurReader +class OurReader { +public: + typedef char Char; + typedef const Char* Location; + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; + }; + + OurReader(OurFeatures const& features); + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + JSONCPP_STRING getFormattedErrorMessages() const; + std::vector getStructuredErrors() const; + bool pushError(const Value& value, const JSONCPP_STRING& message); + bool pushError(const Value& value, + const JSONCPP_STRING& message, + const Value& extra); + bool good() const; + +private: + OurReader(OurReader const&); // no impl + void operator=(OurReader const&); // no impl + + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenNaN, + tokenPosInf, + tokenNegInf, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + JSONCPP_STRING message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + bool readStringSingleQuote(); + bool readNumber(bool checkInf); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, JSONCPP_STRING& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool + addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + JSONCPP_STRING getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + static JSONCPP_STRING normalizeEOL(Location begin, Location end); + static bool containsNewLine(Location begin, Location end); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + JSONCPP_STRING document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + JSONCPP_STRING commentsBefore_; + + OurFeatures const features_; + bool collectComments_; +}; // OurReader + +// complete copy of Read impl, for OurReader + +bool OurReader::containsNewLine(OurReader::Location begin, + OurReader::Location end) { + for (; begin < end; ++begin) + if (*begin == '\n' || *begin == '\r') + return true; + return false; +} + +OurReader::OurReader(OurFeatures const& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(features), collectComments_() { +} + +bool OurReader::parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments) { + if (!features_.allowComments_) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_.clear(); + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (features_.failIfExtra_) { + if ((features_.strictRoot_ || token.type_ != tokenError) && + token.type_ != tokenEndOfStream) { + addError("Extra non-whitespace after JSON value.", token); + return false; + } + } + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) { + if (!root.isArray() && !root.isObject()) { + // Set error location to start of doc, ideally should be first token found + // in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( + "A valid JSON document must be either an array or an object value.", + token); + return false; + } + } + return successful; +} + +bool OurReader::readValue() { + // To preserve the old behaviour we cast size_t to int. + if (static_cast(nodes_.size()) > features_.stackLimit_) + throwRuntimeError("Exceeded stackLimit in readValue()."); + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_.clear(); + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenFalse: { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenNull: { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenNaN: { + Value v(std::numeric_limits::quiet_NaN()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenPosInf: { + Value v(std::numeric_limits::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenNegInf: { + Value v(-std::numeric_limits::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // else, fall through ... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + return successful; +} + +void OurReader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool OurReader::readToken(Token& token) { + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '\'': + if (features_.allowSingleQuotes_) { + token.type_ = tokenString; + ok = readStringSingleQuote(); + break; + } // else fall through + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + token.type_ = tokenNumber; + readNumber(false); + break; + case '-': + if (readNumber(true)) { + token.type_ = tokenNumber; + } else { + token.type_ = tokenNegInf; + ok = features_.allowSpecialFloats_ && match("nfinity", 7); + } + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case 'N': + if (features_.allowSpecialFloats_) { + token.type_ = tokenNaN; + ok = match("aN", 2); + } else { + ok = false; + } + break; + case 'I': + if (features_.allowSpecialFloats_) { + token.type_ = tokenPosInf; + ok = match("nfinity", 7); + } else { + ok = false; + } + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + +void OurReader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool OurReader::match(Location pattern, int patternLength) { + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool OurReader::readComment() { + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if (c == '*') + successful = readCStyleComment(); + else if (c == '/') + successful = readCppStyleComment(); + if (!successful) + return false; + + if (collectComments_) { + CommentPlacement placement = commentBefore; + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (c != '*' || !containsNewLine(commentBegin, current_)) + placement = commentAfterOnSameLine; + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, + OurReader::Location end) { + JSONCPP_STRING normalized; + normalized.reserve(static_cast(end - begin)); + OurReader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void OurReader::addComment(Location begin, + Location end, + CommentPlacement placement) { + assert(collectComments_); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool OurReader::readCStyleComment() { + while ((current_ + 1) < end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool OurReader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +bool OurReader::readNumber(bool checkInf) { + const char* p = current_; + if (checkInf && p != end_ && *p == 'I') { + current_ = ++p; + return false; + } + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : '\0'; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + return true; +} +bool OurReader::readString() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + +bool OurReader::readStringSingleQuote() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '\'') + break; + } + return c == '\''; +} + +bool OurReader::readObject(Token& token) { + Token tokenName; + JSONCPP_STRING name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(token.start_ - begin_); + while (readToken(tokenName)) { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + return true; + name.clear(); + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = numberName.asString(); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover("Missing ':' after object member name", colon, + tokenObjectEnd); + } + if (name.length() >= (1U << 30)) + throwRuntimeError("keylength >= 2^30"); + if (features_.rejectDupKeys_ && currentValue().isMember(name)) { + JSONCPP_STRING msg = "Duplicate key: '" + name + "'"; + return addErrorAndRecover(msg, tokenName, tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment)) { + return addErrorAndRecover("Missing ',' or '}' in object declaration", + comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover("Missing '}' or object member name", tokenName, + tokenObjectEnd); +} + +bool OurReader::readArray(Token& token) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(token.start_ - begin_); + skipSpaces(); + if (current_ != end_ && *current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } + int index = 0; + for (;;) { + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token currentToken; + // Accept Comment after last item in the array. + ok = readToken(currentToken); + while (currentToken.type_ == tokenComment && ok) { + ok = readToken(currentToken); + } + bool badTokenType = (currentToken.type_ != tokenArraySeparator && + currentToken.type_ != tokenArrayEnd); + if (!ok || badTokenType) { + return addErrorAndRecover("Missing ',' or ']' in array declaration", + currentToken, tokenArrayEnd); + } + if (currentToken.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool OurReader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeNumber(Token& token, Value& decoded) { + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if (isNegative) + ++current; + // TODO: Help the compiler do the div and mod at compile time or get rid of + // them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(-Value::minLargestInt) + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(static_cast(c - '0')); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool OurReader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + const int bufferSize = 32; + int count; + ptrdiff_t const length = token.end_ - token.start_; + + // Sanity check to avoid buffer overflow exploits. + if (length < 0) { + return addError("Unable to parse token length", token); + } + size_t const ulength = static_cast(length); + + // Avoid using a string constant for the format control string given to + // sscanf, as this can cause hard to debug crashes on OS X. See here for more + // info: + // + // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html + char format[] = "%lf"; + + if (length <= bufferSize) { + Char buffer[bufferSize + 1]; + memcpy(buffer, token.start_, ulength); + buffer[length] = 0; + fixNumericLocaleInput(buffer, buffer + length); + count = sscanf(buffer, format, &value); + } else { + JSONCPP_STRING buffer(token.start_, token.end_); + count = sscanf(buffer.c_str(), format, &value); + } + + if (count != 1) + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool OurReader::decodeString(Token& token) { + JSONCPP_STRING decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) { + decoded.reserve(static_cast(token.end_ - token.start_ - 2)); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + //printf("-->>>>>>>>>>>>>>>>>>2>>>>>>\n"); + while (current != end) { + Char c = *current++; + if (c == '"') + break; + else if (c == '\\') { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } break; + default: + return addError("Bad escape sequence in string", token, current); + } + } else { + decoded += c; + } + } + return true; +} + +bool OurReader::decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) + return addError( + "additional six characters expected to parse unicode surrogate pair.", + token, current); + if (*(current++) == '\\' && *(current++) == 'u') { + unsigned int surrogatePair; + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } else + return false; + } else + return addError("expecting another \\u token to begin the second half of " + "a unicode surrogate pair", + token, current); + } + return true; +} + +bool OurReader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& ret_unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", token, + current); + int unicode = 0; + for (int index = 0; index < 4; ++index) { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError( + "Bad unicode escape sequence in string: hexadecimal digit expected.", + token, current); + } + ret_unicode = static_cast(unicode); + return true; +} + +bool OurReader::addError(const JSONCPP_STRING& message, + Token& token, + Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool OurReader::recoverFromError(TokenType skipUntilToken) { + size_t errorCount = errors_.size(); + Token skip; + for (;;) { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} + +bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& OurReader::currentValue() { return *(nodes_.top()); } + +OurReader::Char OurReader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void OurReader::getLocationLineAndColumn(Location location, + int& line, + int& column) const { + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) { + Char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + +JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +JSONCPP_STRING OurReader::getFormattedErrorMessages() const { + JSONCPP_STRING formattedMessage; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); ++itError) { + const ErrorInfo& error = *itError; + formattedMessage += + "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += + "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} + +std::vector OurReader::getStructuredErrors() const { + std::vector allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); ++itError) { + const ErrorInfo& error = *itError; + OurReader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) { + ptrdiff_t length = end_ - begin_; + if (value.getOffsetStart() > length || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool OurReader::pushError(const Value& value, + const JSONCPP_STRING& message, + const Value& extra) { + ptrdiff_t length = end_ - begin_; + if (value.getOffsetStart() > length || value.getOffsetLimit() > length || + extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool OurReader::good() const { return !errors_.size(); } + +class OurCharReader : public CharReader { + bool const collectComments_; + OurReader reader_; + +public: + OurCharReader(bool collectComments, OurFeatures const& features) + : collectComments_(collectComments), reader_(features) {} + bool parse(char const* beginDoc, + char const* endDoc, + Value* root, + JSONCPP_STRING* errs) JSONCPP_OVERRIDE { + bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); + if (errs) { + *errs = reader_.getFormattedErrorMessages(); + } + return ok; + } +}; + +CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); } +CharReaderBuilder::~CharReaderBuilder() {} +CharReader* CharReaderBuilder::newCharReader() const { + bool collectComments = settings_["collectComments"].asBool(); + OurFeatures features = OurFeatures::all(); + features.allowComments_ = settings_["allowComments"].asBool(); + features.strictRoot_ = settings_["strictRoot"].asBool(); + features.allowDroppedNullPlaceholders_ = + settings_["allowDroppedNullPlaceholders"].asBool(); + features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); + features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); + features.stackLimit_ = settings_["stackLimit"].asInt(); + features.failIfExtra_ = settings_["failIfExtra"].asBool(); + features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); + features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); + return new OurCharReader(collectComments, features); +} +static void getValidReaderKeys(std::set* valid_keys) { + valid_keys->clear(); + valid_keys->insert("collectComments"); + valid_keys->insert("allowComments"); + valid_keys->insert("strictRoot"); + valid_keys->insert("allowDroppedNullPlaceholders"); + valid_keys->insert("allowNumericKeys"); + valid_keys->insert("allowSingleQuotes"); + valid_keys->insert("stackLimit"); + valid_keys->insert("failIfExtra"); + valid_keys->insert("rejectDupKeys"); + valid_keys->insert("allowSpecialFloats"); +} +bool CharReaderBuilder::validate(Json::Value* invalid) const { + Json::Value my_invalid; + if (!invalid) + invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set valid_keys; + getValidReaderKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + JSONCPP_STRING const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& CharReaderBuilder::operator[](JSONCPP_STRING key) { + return settings_[key]; +} +// static +void CharReaderBuilder::strictMode(Json::Value* settings) { + //! [CharReaderBuilderStrictMode] + (*settings)["allowComments"] = false; + (*settings)["strictRoot"] = true; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = true; + (*settings)["rejectDupKeys"] = true; + (*settings)["allowSpecialFloats"] = false; + //! [CharReaderBuilderStrictMode] +} +// static +void CharReaderBuilder::setDefaults(Json::Value* settings) { + //! [CharReaderBuilderDefaults] + (*settings)["collectComments"] = true; + (*settings)["allowComments"] = true; + (*settings)["strictRoot"] = false; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = false; + (*settings)["rejectDupKeys"] = false; + (*settings)["allowSpecialFloats"] = false; + //! [CharReaderBuilderDefaults] +} + +////////////////////////////////// +// global functions + +bool parseFromStream(CharReader::Factory const& fact, + JSONCPP_ISTREAM& sin, + Value* root, + JSONCPP_STRING* errs) { + JSONCPP_OSTRINGSTREAM ssin; + ssin << sin.rdbuf(); + JSONCPP_STRING doc = ssin.str(); + char const* begin = doc.data(); + char const* end = begin + doc.size(); + // Note that we do not actually need a null-terminator. + CharReaderPtr const reader(fact.newCharReader()); + return reader->parse(begin, end, root, errs); +} + +JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) { + CharReaderBuilder b; + JSONCPP_STRING errs; + bool ok = parseFromStream(b, sin, &root, &errs); + if (!ok) { + throwRuntimeError(errs); + } + return sin; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_valueiterator.inl +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +// included by json_value.cpp + +namespace Json { + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIteratorBase +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIteratorBase::ValueIteratorBase() + : current_(), isNull_(true) { +} + +ValueIteratorBase::ValueIteratorBase( + const Value::ObjectValues::iterator& current) + : current_(current), isNull_(false) {} + +Value& ValueIteratorBase::deref() const { + return current_->second; +} + +void ValueIteratorBase::increment() { + ++current_; +} + +void ValueIteratorBase::decrement() { + --current_; +} + +ValueIteratorBase::difference_type +ValueIteratorBase::computeDistance(const SelfType& other) const { +#ifdef JSON_USE_CPPTL_SMALLMAP + return other.current_ - current_; +#else + // Iterator for null value are initialized using the default + // constructor, which initialize current_ to the default + // std::map::iterator. As begin() and end() are two instance + // of the default std::map::iterator, they can not be compared. + // To allow this, we handle this comparison specifically. + if (isNull_ && other.isNull_) { + return 0; + } + + // Usage of std::distance is not portable (does not compile with Sun Studio 12 + // RogueWave STL, + // which is the one used by default). + // Using a portable hand-made version for non random iterator instead: + // return difference_type( std::distance( current_, other.current_ ) ); + difference_type myDistance = 0; + for (Value::ObjectValues::iterator it = current_; it != other.current_; + ++it) { + ++myDistance; + } + return myDistance; +#endif +} + +bool ValueIteratorBase::isEqual(const SelfType& other) const { + if (isNull_) { + return other.isNull_; + } + return current_ == other.current_; +} + +void ValueIteratorBase::copy(const SelfType& other) { + current_ = other.current_; + isNull_ = other.isNull_; +} + +Value ValueIteratorBase::key() const { + const Value::CZString czstring = (*current_).first; + if (czstring.data()) { + if (czstring.isStaticString()) + return Value(StaticString(czstring.data())); + return Value(czstring.data(), czstring.data() + czstring.length()); + } + return Value(czstring.index()); +} + +UInt ValueIteratorBase::index() const { + const Value::CZString czstring = (*current_).first; + if (!czstring.data()) + return czstring.index(); + return Value::UInt(-1); +} + +JSONCPP_STRING ValueIteratorBase::name() const { + char const* keey; + char const* end; + keey = memberName(&end); + if (!keey) return JSONCPP_STRING(); + return JSONCPP_STRING(keey, end); +} + +char const* ValueIteratorBase::memberName() const { + const char* cname = (*current_).first.data(); + return cname ? cname : ""; +} + +char const* ValueIteratorBase::memberName(char const** end) const { + const char* cname = (*current_).first.data(); + if (!cname) { + *end = NULL; + return NULL; + } + *end = cname + (*current_).first.length(); + return cname; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueConstIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueConstIterator::ValueConstIterator() {} + +ValueConstIterator::ValueConstIterator( + const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueConstIterator::ValueConstIterator(ValueIterator const& other) + : ValueIteratorBase(other) {} + +ValueConstIterator& ValueConstIterator:: +operator=(const ValueIteratorBase& other) { + copy(other); + return *this; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIterator::ValueIterator() {} + +ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueIterator::ValueIterator(const ValueConstIterator& other) + : ValueIteratorBase(other) { + throwRuntimeError("ConstIterator to Iterator should never be allowed."); +} + +ValueIterator::ValueIterator(const ValueIterator& other) + : ValueIteratorBase(other) {} + +ValueIterator& ValueIterator::operator=(const SelfType& other) { + copy(other); + return *this; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_valueiterator.inl +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_value.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#ifdef JSON_USE_CPPTL +#include +#endif +#include // min() +#include // size_t + +// Disable warning C4702 : unreachable code +#if defined(_MSC_VER) && _MSC_VER >= 1800 // VC++ 12.0 and above +#pragma warning(disable : 4702) +#endif + +#define JSON_ASSERT_UNREACHABLE assert(false) + +namespace Json { + +// This is a walkaround to avoid the static initialization of Value::null. +// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of +// 8 (instead of 4) as a bit of future-proofing. +#if defined(__ARMEL__) +#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) +#else +#define ALIGNAS(byte_alignment) +#endif +// static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; +// const unsigned char& kNullRef = kNull[0]; +// const Value& Value::null = reinterpret_cast(kNullRef); +// const Value& Value::nullRef = null; + +// static +Value const& Value::nullSingleton() { + static Value const nullStatic; + return nullStatic; +} + +// for backwards compatibility, we'll leave these global references around, but +// DO NOT use them in JSONCPP library code any more! +Value const& Value::null = Value::nullSingleton(); +Value const& Value::nullRef = Value::nullSingleton(); + +const Int Value::minInt = Int(~(UInt(-1) / 2)); +const Int Value::maxInt = Int(UInt(-1) / 2); +const UInt Value::maxUInt = UInt(-1); +#if defined(JSON_HAS_INT64) +const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); +const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); +const UInt64 Value::maxUInt64 = UInt64(-1); +// The constant is hard-coded because some compiler have trouble +// converting Value::maxUInt64 to a double correctly (AIX/xlC). +// Assumes that UInt64 is a 64 bits integer. +static const double maxUInt64AsDouble = 18446744073709551615.0; +#endif // defined(JSON_HAS_INT64) +const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); +const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); +const LargestUInt Value::maxLargestUInt = LargestUInt(-1); + +const UInt Value::defaultRealPrecision = 17; + +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +template +static inline bool InRange(double d, T min, U max) { + // The casts can lose precision, but we are looking only for + // an approximate range. Might fail on edge cases though. ~cdunn + // return d >= static_cast(min) && d <= static_cast(max); + return d >= min && d <= max; +} +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +static inline double integerToDouble(Json::UInt64 value) { + return static_cast(Int64(value / 2)) * 2.0 + + static_cast(Int64(value & 1)); +} + +template static inline double integerToDouble(T value) { + return static_cast(value); +} + +template +static inline bool InRange(double d, T min, U max) { + return d >= integerToDouble(min) && d <= integerToDouble(max); +} +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + +/** Duplicates the specified string value. + * @param value Pointer to the string to duplicate. Must be zero-terminated if + * length is "unknown". + * @param length Length of the value. if equals to unknown, then it will be + * computed using strlen(value). + * @return Pointer on the duplicate instance of string. + */ +static inline char* duplicateStringValue(const char* value, size_t length) { + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + if (length >= static_cast(Value::maxInt)) + length = Value::maxInt - 1; + + char* newString = static_cast(malloc(length + 1)); + if (newString == NULL) { + throwRuntimeError("in Json::Value::duplicateStringValue(): " + "Failed to allocate string value buffer"); + } + memcpy(newString, value, length); + newString[length] = 0; + return newString; +} + +/* Record the length as a prefix. + */ +static inline char* duplicateAndPrefixStringValue(const char* value, + unsigned int length) { + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + JSON_ASSERT_MESSAGE(length <= static_cast(Value::maxInt) - + sizeof(unsigned) - 1U, + "in Json::Value::duplicateAndPrefixStringValue(): " + "length too big for prefixing"); + unsigned actualLength = length + static_cast(sizeof(unsigned)) + 1U; + char* newString = static_cast(malloc(actualLength)); + if (newString == 0) { + throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): " + "Failed to allocate string value buffer"); + } + *reinterpret_cast(newString) = length; + memcpy(newString + sizeof(unsigned), value, length); + newString[actualLength - 1U] = + 0; // to avoid buffer over-run accidents by users later + return newString; +} +inline static void decodePrefixedString(bool isPrefixed, + char const* prefixed, + unsigned* length, + char const** value) { + if (!isPrefixed) { + *length = static_cast(strlen(prefixed)); + *value = prefixed; + } else { + *length = *reinterpret_cast(prefixed); + *value = prefixed + sizeof(unsigned); + } +} +/** Free the string duplicated by + * duplicateStringValue()/duplicateAndPrefixStringValue(). + */ +#if JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { + unsigned length = 0; + char const* valueDecoded; + decodePrefixedString(true, value, &length, &valueDecoded); + size_t const size = sizeof(unsigned) + length + 1U; + memset(value, 0, size); + free(value); +} +static inline void releaseStringValue(char* value, unsigned length) { + // length==0 => we allocated the strings memory + size_t size = (length == 0) ? strlen(value) : length; + memset(value, 0, size); + free(value); +} +#else // !JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { free(value); } +static inline void releaseStringValue(char* value, unsigned) { free(value); } +#endif // JSONCPP_USING_SECURE_MEMORY + +} // namespace Json + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#if !defined(JSON_IS_AMALGAMATION) + +#include "json_valueiterator.inl" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +Exception::Exception(JSONCPP_STRING const& msg) : msg_(msg) {} +Exception::~Exception() JSONCPP_NOEXCEPT {} +char const* Exception::what() const JSONCPP_NOEXCEPT { return msg_.c_str(); } +RuntimeError::RuntimeError(JSONCPP_STRING const& msg) : Exception(msg) {} +LogicError::LogicError(JSONCPP_STRING const& msg) : Exception(msg) {} +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) { + throw RuntimeError(msg); +} +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) { + throw LogicError(msg); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CommentInfo +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +Value::CommentInfo::CommentInfo() : comment_(0) {} + +Value::CommentInfo::~CommentInfo() { + if (comment_) + releaseStringValue(comment_, 0u); +} + +void Value::CommentInfo::setComment(const char* text, size_t len) { + if (comment_) { + releaseStringValue(comment_, 0u); + comment_ = 0; + } + JSON_ASSERT(text != 0); + JSON_ASSERT_MESSAGE( + text[0] == '\0' || text[0] == '/', + "in Json::Value::setComment(): Comments must start with /"); + // It seems that /**/ style comments are acceptable as well. + comment_ = duplicateStringValue(text, len); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CZString +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +// Notes: policy_ indicates if the string was allocated when +// a string is stored. + +Value::CZString::CZString(ArrayIndex index) : cstr_(0), index_(index) {} + +Value::CZString::CZString(char const* str, + unsigned length, + DuplicationPolicy allocate) + : cstr_(str) { + // allocate != duplicate + storage_.policy_ = allocate & 0x3; + storage_.length_ = length & 0x3FFFFFFF; +} + +Value::CZString::CZString(const CZString& other) { + cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 0 + ? duplicateStringValue(other.cstr_, other.storage_.length_) + : other.cstr_); + storage_.policy_ = + static_cast( + other.cstr_ + ? (static_cast(other.storage_.policy_) == + noDuplication + ? noDuplication + : duplicate) + : static_cast(other.storage_.policy_)) & + 3U; + storage_.length_ = other.storage_.length_; +} + +#if JSON_HAS_RVALUE_REFERENCES +Value::CZString::CZString(CZString&& other) + : cstr_(other.cstr_), index_(other.index_) { + other.cstr_ = nullptr; +} +#endif + +Value::CZString::~CZString() { + if (cstr_ && storage_.policy_ == duplicate) { + releaseStringValue(const_cast(cstr_), + storage_.length_ + 1u); // +1 for null terminating + // character for sake of + // completeness but not actually + // necessary + } +} + +void Value::CZString::swap(CZString& other) { + std::swap(cstr_, other.cstr_); + std::swap(index_, other.index_); +} + +Value::CZString& Value::CZString::operator=(const CZString& other) { + cstr_ = other.cstr_; + index_ = other.index_; + return *this; +} + +#if JSON_HAS_RVALUE_REFERENCES +Value::CZString& Value::CZString::operator=(CZString&& other) { + cstr_ = other.cstr_; + index_ = other.index_; + other.cstr_ = nullptr; + return *this; +} +#endif + +bool Value::CZString::operator<(const CZString& other) const { + if (!cstr_) + return index_ < other.index_; + // return strcmp(cstr_, other.cstr_) < 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + unsigned min_len = std::min(this_len, other_len); + JSON_ASSERT(this->cstr_ && other.cstr_); + int comp = memcmp(this->cstr_, other.cstr_, min_len); + if (comp < 0) + return true; + if (comp > 0) + return false; + return (this_len < other_len); +} + +bool Value::CZString::operator==(const CZString& other) const { + if (!cstr_) + return index_ == other.index_; + // return strcmp(cstr_, other.cstr_) == 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + if (this_len != other_len) + return false; + JSON_ASSERT(this->cstr_ && other.cstr_); + int comp = memcmp(this->cstr_, other.cstr_, this_len); + return comp == 0; +} + +ArrayIndex Value::CZString::index() const { return index_; } + +// const char* Value::CZString::c_str() const { return cstr_; } +const char* Value::CZString::data() const { return cstr_; } +unsigned Value::CZString::length() const { return storage_.length_; } +bool Value::CZString::isStaticString() const { + return storage_.policy_ == noDuplication; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::Value +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +/*! \internal Default constructor initialization must be equivalent to: + * memset( this, 0, sizeof(Value) ) + * This optimization is used in ValueInternalMap fast allocator. + */ +Value::Value(ValueType type) { + static char const emptyString[] = ""; + initBasic(type); + switch (type) { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + // allocated_ == false, so this is safe. + value_.string_ = const_cast(static_cast(emptyString)); + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +Value::Value(Int value) { + initBasic(intValue); + value_.int_ = value; +} + +Value::Value(UInt value) { + initBasic(uintValue); + value_.uint_ = value; +} +#if defined(JSON_HAS_INT64) +Value::Value(Int64 value) { + initBasic(intValue); + value_.int_ = value; +} +Value::Value(UInt64 value) { + initBasic(uintValue); + value_.uint_ = value; +} +#endif // defined(JSON_HAS_INT64) + +Value::Value(double value) { + initBasic(realValue); + value_.real_ = value; +} + +Value::Value(const char* value) { + initBasic(stringValue, true); + JSON_ASSERT_MESSAGE(value != NULL, "Null Value Passed to Value Constructor"); + value_.string_ = duplicateAndPrefixStringValue( + value, static_cast(strlen(value))); +} + +Value::Value(const char* begin, const char* end) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(begin, static_cast(end - begin)); +} + +Value::Value(const JSONCPP_STRING& value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue( + value.data(), static_cast(value.length())); +} + +Value::Value(const StaticString& value) { + initBasic(stringValue); + value_.string_ = const_cast(value.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value::Value(const CppTL::ConstString& value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue( + value, static_cast(value.length())); +} +#endif + +Value::Value(bool value) { + initBasic(booleanValue); + value_.bool_ = value; +} + +Value::Value(const Value& other) { + dupPayload(other); + dupMeta(other); +} + +#if JSON_HAS_RVALUE_REFERENCES +// Move constructor +Value::Value(Value&& other) { + initBasic(nullValue); + swap(other); +} +#endif + +Value::~Value() { + releasePayload(); + + delete[] comments_; + + value_.uint_ = 0; +} + +Value& Value::operator=(Value other) { + swap(other); + return *this; +} + +void Value::swapPayload(Value& other) { + ValueType temp = type_; + type_ = other.type_; + other.type_ = temp; + std::swap(value_, other.value_); + int temp2 = allocated_; + allocated_ = other.allocated_; + other.allocated_ = temp2 & 0x1; +} + +void Value::copyPayload(const Value& other) { + releasePayload(); + dupPayload(other); +} + +void Value::swap(Value& other) { + swapPayload(other); + std::swap(comments_, other.comments_); + std::swap(start_, other.start_); + std::swap(limit_, other.limit_); +} + +void Value::copy(const Value& other) { + copyPayload(other); + delete[] comments_; + dupMeta(other); +} + +ValueType Value::type() const { return type_; } + +int Value::compare(const Value& other) const { + if (*this < other) + return -1; + if (*this > other) + return 1; + return 0; +} + +bool Value::operator<(const Value& other) const { + int typeDelta = type_ - other.type_; + if (typeDelta) + return typeDelta < 0 ? true : false; + switch (type_) { + case nullValue: + return false; + case intValue: + return value_.int_ < other.value_.int_; + case uintValue: + return value_.uint_ < other.value_.uint_; + case realValue: + return value_.real_ < other.value_.real_; + case booleanValue: + return value_.bool_ < other.value_.bool_; + case stringValue: { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + if (other.value_.string_) + return true; + else + return false; + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, + &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, + &other_str); + unsigned min_len = std::min(this_len, other_len); + JSON_ASSERT(this_str && other_str); + int comp = memcmp(this_str, other_str, min_len); + if (comp < 0) + return true; + if (comp > 0) + return false; + return (this_len < other_len); + } + case arrayValue: + case objectValue: { + int delta = int(value_.map_->size() - other.value_.map_->size()); + if (delta) + return delta < 0; + return (*value_.map_) < (*other.value_.map_); + } + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator<=(const Value& other) const { return !(other < *this); } + +bool Value::operator>=(const Value& other) const { return !(*this < other); } + +bool Value::operator>(const Value& other) const { return other < *this; } + +bool Value::operator==(const Value& other) const { + // if ( type_ != other.type_ ) + // GCC 2.95.3 says: + // attempt to take address of bit-field structure member `Json::Value::type_' + // Beats me, but a temp solves the problem. + int temp = other.type_; + if (type_ != temp) + return false; + switch (type_) { + case nullValue: + return true; + case intValue: + return value_.int_ == other.value_.int_; + case uintValue: + return value_.uint_ == other.value_.uint_; + case realValue: + return value_.real_ == other.value_.real_; + case booleanValue: + return value_.bool_ == other.value_.bool_; + case stringValue: { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + return (value_.string_ == other.value_.string_); + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, + &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, + &other_str); + if (this_len != other_len) + return false; + JSON_ASSERT(this_str && other_str); + int comp = memcmp(this_str, other_str, this_len); + return comp == 0; + } + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() && + (*value_.map_) == (*other.value_.map_); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator!=(const Value& other) const { return !(*this == other); } + +const char* Value::asCString() const { + JSON_ASSERT_MESSAGE(type_ == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) + return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, + &this_str); + return this_str; +} + +#if JSONCPP_USING_SECURE_MEMORY +unsigned Value::getCStringLength() const { + JSON_ASSERT_MESSAGE(type_ == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) + return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, + &this_str); + return this_len; +} +#endif + +bool Value::getString(char const** begin, char const** end) const { + if (type_ != stringValue) + return false; + if (value_.string_ == 0) + return false; + unsigned length; + decodePrefixedString(this->allocated_, this->value_.string_, &length, begin); + *end = *begin + length; + return true; +} + +JSONCPP_STRING Value::asString() const { + switch (type_) { + case nullValue: + return ""; + case stringValue: { + if (value_.string_ == 0) + return ""; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, + &this_str); + return JSONCPP_STRING(this_str, this_len); + } + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + return valueToString(value_.int_); + case uintValue: + return valueToString(value_.uint_); + case realValue: + return valueToString(value_.real_); + default: + JSON_FAIL_MESSAGE("Type is not convertible to string"); + } +} + +#ifdef JSON_USE_CPPTL +CppTL::ConstString Value::asConstString() const { + unsigned len; + char const* str; + decodePrefixedString(allocated_, value_.string_, &len, &str); + return CppTL::ConstString(str, len); +} +#endif + +Value::Int Value::asInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); + return Int(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); + return Int(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), + "double out of Int range"); + return Int(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int."); +} + +Value::UInt Value::asUInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); + return UInt(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); + return UInt(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), + "double out of UInt range"); + return UInt(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt."); +} + +#if defined(JSON_HAS_INT64) + +Value::Int64 Value::asInt64() const { + switch (type_) { + case intValue: + return Int64(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); + return Int64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), + "double out of Int64 range"); + return Int64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int64."); +} + +Value::UInt64 Value::asUInt64() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); + return UInt64(value_.int_); + case uintValue: + return UInt64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), + "double out of UInt64 range"); + return UInt64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); +} +#endif // if defined(JSON_HAS_INT64) + +LargestInt Value::asLargestInt() const { +#if defined(JSON_NO_INT64) + return asInt(); +#else + return asInt64(); +#endif +} + +LargestUInt Value::asLargestUInt() const { +#if defined(JSON_NO_INT64) + return asUInt(); +#else + return asUInt64(); +#endif +} + +double Value::asDouble() const { + switch (type_) { + case intValue: + return static_cast(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return integerToDouble(value_.uint_); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return value_.real_; + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to double."); +} + +float Value::asFloat() const { + switch (type_) { + case intValue: + return static_cast(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + // This can fail (silently?) if the value is bigger than MAX_FLOAT. + return static_cast(integerToDouble(value_.uint_)); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return static_cast(value_.real_); + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0f : 0.0f; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to float."); +} + +bool Value::asBool() const { + switch (type_) { + case booleanValue: + return value_.bool_; + case nullValue: + return false; + case intValue: + return value_.int_ ? true : false; + case uintValue: + return value_.uint_ ? true : false; + case realValue: + // This is kind of strange. Not recommended. + return (value_.real_ != 0.0) ? true : false; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to bool."); +} + +bool Value::isConvertibleTo(ValueType other) const { + switch (other) { + case nullValue: + return (isNumeric() && asDouble() == 0.0) || + (type_ == booleanValue && value_.bool_ == false) || + (type_ == stringValue && asString().empty()) || + (type_ == arrayValue && value_.map_->size() == 0) || + (type_ == objectValue && value_.map_->size() == 0) || + type_ == nullValue; + case intValue: + return isInt() || + (type_ == realValue && InRange(value_.real_, minInt, maxInt)) || + type_ == booleanValue || type_ == nullValue; + case uintValue: + return isUInt() || + (type_ == realValue && InRange(value_.real_, 0, maxUInt)) || + type_ == booleanValue || type_ == nullValue; + case realValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case booleanValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case stringValue: + return isNumeric() || type_ == booleanValue || type_ == stringValue || + type_ == nullValue; + case arrayValue: + return type_ == arrayValue || type_ == nullValue; + case objectValue: + return type_ == objectValue || type_ == nullValue; + } + JSON_ASSERT_UNREACHABLE; + return false; +} + +/// Number of values in array or object +ArrayIndex Value::size() const { + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + case stringValue: + return 0; + case arrayValue: // size of the array is highest index + 1 + if (!value_.map_->empty()) { + ObjectValues::const_iterator itLast = value_.map_->end(); + --itLast; + return (*itLast).first.index() + 1; + } + return 0; + case objectValue: + return ArrayIndex(value_.map_->size()); + } + JSON_ASSERT_UNREACHABLE; + return 0; // unreachable; +} + +bool Value::empty() const { + if (isNull() || isArray() || isObject()) + return size() == 0u; + else + return false; +} + +Value::operator bool() const { return !isNull(); } + +void Value::clear() { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || + type_ == objectValue, + "in Json::Value::clear(): requires complex value"); + start_ = 0; + limit_ = 0; + switch (type_) { + case arrayValue: + case objectValue: + value_.map_->clear(); + break; + default: + break; + } +} + +void Value::resize(ArrayIndex newSize) { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue, + "in Json::Value::resize(): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + ArrayIndex oldSize = size(); + if (newSize == 0) + clear(); + else if (newSize > oldSize) + this->operator[](newSize - 1); + else { + for (ArrayIndex index = newSize; index < oldSize; ++index) { + value_.map_->erase(index); + } + JSON_ASSERT(size() == newSize); + } +} + +Value& Value::operator[](ArrayIndex index) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + CZString key(index); + ObjectValues::iterator it = value_.map_->lower_bound(key); + if (it != value_.map_->end() && (*it).first == key) + return (*it).second; + + ObjectValues::value_type defaultValue(key, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + return (*it).second; +} + +Value& Value::operator[](int index) { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index): index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +const Value& Value::operator[](ArrayIndex index) const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); + if (type_ == nullValue) + return nullSingleton(); + CZString key(index); + ObjectValues::const_iterator it = value_.map_->find(key); + if (it == value_.map_->end()) + return nullSingleton(); + return (*it).second; +} + +const Value& Value::operator[](int index) const { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index) const: index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +void Value::initBasic(ValueType type, bool allocated) { + type_ = type; + allocated_ = allocated; + comments_ = 0; + start_ = 0; + limit_ = 0; +} + +void Value::dupPayload(const Value& other) { + type_ = other.type_; + allocated_ = false; + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if (other.value_.string_ && other.allocated_) { + unsigned len; + char const* str; + decodePrefixedString(other.allocated_, other.value_.string_, &len, &str); + value_.string_ = duplicateAndPrefixStringValue(str, len); + allocated_ = true; + } else { + value_.string_ = other.value_.string_; + } + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(*other.value_.map_); + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +void Value::releasePayload() { + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if (allocated_) + releasePrefixedStringValue(value_.string_); + break; + case arrayValue: + case objectValue: + delete value_.map_; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +void Value::dupMeta(const Value& other) { + if (other.comments_) { + comments_ = new CommentInfo[numberOfCommentPlacement]; + for (int comment = 0; comment < numberOfCommentPlacement; ++comment) { + const CommentInfo& otherComment = other.comments_[comment]; + if (otherComment.comment_) + comments_[comment].setComment(otherComment.comment_, + strlen(otherComment.comment_)); + } + } else { + comments_ = 0; + } + start_ = other.start_; + limit_ = other.limit_; +} + +// Access an object value by name, create a null member if it does not exist. +// @pre Type of '*this' is object or null. +// @param key is null-terminated. +Value& Value::resolveReference(const char* key) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey(key, static_cast(strlen(key)), + CZString::noDuplication); // NOTE! + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +// @param key is not null-terminated. +Value& Value::resolveReference(char const* key, char const* end) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(key, end): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey(key, static_cast(end - key), + CZString::duplicateOnCopy); + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +Value Value::get(ArrayIndex index, const Value& defaultValue) const { + const Value* value = &((*this)[index]); + return value == &nullSingleton() ? defaultValue : *value; +} + +bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } + +Value const* Value::find(char const* begin, char const* end) const { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, + "in Json::Value::find(key, end, found): requires " + "objectValue or nullValue"); + if (type_ == nullValue) + return NULL; + CZString actualKey(begin, static_cast(end - begin), + CZString::noDuplication); + ObjectValues::const_iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return NULL; + return &(*it).second; +} +const Value& Value::operator[](const char* key) const { + Value const* found = find(key, key + strlen(key)); + if (!found) + return nullSingleton(); + return *found; +} +Value const& Value::operator[](JSONCPP_STRING const& key) const { + Value const* found = find(key.data(), key.data() + key.length()); + if (!found) + return nullSingleton(); + return *found; +} + +Value& Value::operator[](const char* key) { + return resolveReference(key, key + strlen(key)); +} + +Value& Value::operator[](const JSONCPP_STRING& key) { + return resolveReference(key.data(), key.data() + key.length()); +} + +Value& Value::operator[](const StaticString& key) { + return resolveReference(key.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value& Value::operator[](const CppTL::ConstString& key) { + return resolveReference(key.c_str(), key.end_c_str()); +} +Value const& Value::operator[](CppTL::ConstString const& key) const { + Value const* found = find(key.c_str(), key.end_c_str()); + if (!found) + return nullSingleton(); + return *found; +} +#endif + +Value& Value::append(const Value& value) { return (*this)[size()] = value; } + +#if JSON_HAS_RVALUE_REFERENCES +Value& Value::append(Value&& value) { + return (*this)[size()] = std::move(value); +} +#endif + +Value Value::get(char const* begin, + char const* end, + Value const& defaultValue) const { + Value const* found = find(begin, end); + return !found ? defaultValue : *found; +} +Value Value::get(char const* key, Value const& defaultValue) const { + return get(key, key + strlen(key), defaultValue); +} +Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue) const { + return get(key.data(), key.data() + key.length(), defaultValue); +} + +bool Value::removeMember(const char* begin, const char* end, Value* removed) { + if (type_ != objectValue) { + return false; + } + CZString actualKey(begin, static_cast(end - begin), + CZString::noDuplication); + ObjectValues::iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return false; + if (removed) +#if JSON_HAS_RVALUE_REFERENCES + *removed = std::move(it->second); +#else + *removed = it->second; +#endif + value_.map_->erase(it); + return true; +} +bool Value::removeMember(const char* key, Value* removed) { + return removeMember(key, key + strlen(key), removed); +} +bool Value::removeMember(JSONCPP_STRING const& key, Value* removed) { + return removeMember(key.data(), key.data() + key.length(), removed); +} +void Value::removeMember(const char* key) { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, + "in Json::Value::removeMember(): requires objectValue"); + if (type_ == nullValue) + return; + + CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication); + value_.map_->erase(actualKey); +} +void Value::removeMember(const JSONCPP_STRING& key) { + removeMember(key.c_str()); +} + +bool Value::removeIndex(ArrayIndex index, Value* removed) { + if (type_ != arrayValue) { + return false; + } + CZString key(index); + ObjectValues::iterator it = value_.map_->find(key); + if (it == value_.map_->end()) { + return false; + } + if (removed) + *removed = it->second; + ArrayIndex oldSize = size(); + // shift left all items left, into the place of the "removed" + for (ArrayIndex i = index; i < (oldSize - 1); ++i) { + CZString keey(i); + (*value_.map_)[keey] = (*this)[i + 1]; + } + // erase the last one ("leftover") + CZString keyLast(oldSize - 1); + ObjectValues::iterator itLast = value_.map_->find(keyLast); + value_.map_->erase(itLast); + return true; +} + +#ifdef JSON_USE_CPPTL +Value Value::get(const CppTL::ConstString& key, + const Value& defaultValue) const { + return get(key.c_str(), key.end_c_str(), defaultValue); +} +#endif + +bool Value::isMember(char const* begin, char const* end) const { + Value const* value = find(begin, end); + return NULL != value; +} +bool Value::isMember(char const* key) const { + return isMember(key, key + strlen(key)); +} +bool Value::isMember(JSONCPP_STRING const& key) const { + return isMember(key.data(), key.data() + key.length()); +} + +#ifdef JSON_USE_CPPTL +bool Value::isMember(const CppTL::ConstString& key) const { + return isMember(key.c_str(), key.end_c_str()); +} +#endif + +Value::Members Value::getMemberNames() const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::getMemberNames(), value must be objectValue"); + if (type_ == nullValue) + return Value::Members(); + Members members; + members.reserve(value_.map_->size()); + ObjectValues::const_iterator it = value_.map_->begin(); + ObjectValues::const_iterator itEnd = value_.map_->end(); + for (; it != itEnd; ++it) { + members.push_back(JSONCPP_STRING((*it).first.data(), (*it).first.length())); + } + return members; +} +// +//# ifdef JSON_USE_CPPTL +// EnumMemberNames +// Value::enumMemberNames() const +//{ +// if ( type_ == objectValue ) +// { +// return CppTL::Enum::any( CppTL::Enum::transform( +// CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), +// MemberNamesTransform() ) ); +// } +// return EnumMemberNames(); +//} +// +// +// EnumValues +// Value::enumValues() const +//{ +// if ( type_ == objectValue || type_ == arrayValue ) +// return CppTL::Enum::anyValues( *(value_.map_), +// CppTL::Type() ); +// return EnumValues(); +//} +// +//# endif + +static bool IsIntegral(double d) { + double integral_part; + return modf(d, &integral_part) == 0.0; +} + +bool Value::isNull() const { return type_ == nullValue; } + +bool Value::isBool() const { return type_ == booleanValue; } + +bool Value::isInt() const { + switch (type_) { + case intValue: +#if defined(JSON_HAS_INT64) + return value_.int_ >= minInt && value_.int_ <= maxInt; +#else + return true; +#endif + case uintValue: + return value_.uint_ <= UInt(maxInt); + case realValue: + return value_.real_ >= minInt && value_.real_ <= maxInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isUInt() const { + switch (type_) { + case intValue: +#if defined(JSON_HAS_INT64) + return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); +#else + return value_.int_ >= 0; +#endif + case uintValue: +#if defined(JSON_HAS_INT64) + return value_.uint_ <= maxUInt; +#else + return true; +#endif + case realValue: + return value_.real_ >= 0 && value_.real_ <= maxUInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return true; + case uintValue: + return value_.uint_ <= UInt64(maxInt64); + case realValue: + // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a + // double, so double(maxInt64) will be rounded up to 2^63. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < double(maxInt64) && IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isUInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return value_.int_ >= 0; + case uintValue: + return true; + case realValue: + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && + IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isIntegral() const { + switch (type_) { + case intValue: + case uintValue: + return true; + case realValue: +#if defined(JSON_HAS_INT64) + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_); +#else + return value_.real_ >= minInt && value_.real_ <= maxUInt && + IsIntegral(value_.real_); +#endif // JSON_HAS_INT64 + default: + break; + } + return false; +} + +bool Value::isDouble() const { + return type_ == intValue || type_ == uintValue || type_ == realValue; +} + +bool Value::isNumeric() const { return isDouble(); } + +bool Value::isString() const { return type_ == stringValue; } + +bool Value::isArray() const { return type_ == arrayValue; } + +bool Value::isObject() const { return type_ == objectValue; } + +void Value::setComment(const char* comment, + size_t len, + CommentPlacement placement) { + if (!comments_) + comments_ = new CommentInfo[numberOfCommentPlacement]; + if ((len > 0) && (comment[len - 1] == '\n')) { + // Always discard trailing newline, to aid indentation. + len -= 1; + } + comments_[placement].setComment(comment, len); +} + +void Value::setComment(const char* comment, CommentPlacement placement) { + setComment(comment, strlen(comment), placement); +} + +void Value::setComment(const JSONCPP_STRING& comment, + CommentPlacement placement) { + setComment(comment.c_str(), comment.length(), placement); +} + +bool Value::hasComment(CommentPlacement placement) const { + return comments_ != 0 && comments_[placement].comment_ != 0; +} + +JSONCPP_STRING Value::getComment(CommentPlacement placement) const { + if (hasComment(placement)) + return comments_[placement].comment_; + return ""; +} + +void Value::setOffsetStart(ptrdiff_t start) { start_ = start; } + +void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; } + +ptrdiff_t Value::getOffsetStart() const { return start_; } + +ptrdiff_t Value::getOffsetLimit() const { return limit_; } + +JSONCPP_STRING Value::toStyledString() const { + StreamWriterBuilder builder; + + JSONCPP_STRING out = this->hasComment(commentBefore) ? "\n" : ""; + out += Json::writeString(builder, *this); + out += '\n'; + + return out; +} + +Value::const_iterator Value::begin() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->begin()); + break; + default: + break; + } + return const_iterator(); +} + +Value::const_iterator Value::end() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->end()); + break; + default: + break; + } + return const_iterator(); +} + +Value::iterator Value::begin() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->begin()); + break; + default: + break; + } + return iterator(); +} + +Value::iterator Value::end() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->end()); + break; + default: + break; + } + return iterator(); +} + +// class PathArgument +// ////////////////////////////////////////////////////////////////// + +PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} + +PathArgument::PathArgument(ArrayIndex index) + : key_(), index_(index), kind_(kindIndex) {} + +PathArgument::PathArgument(const char* key) + : key_(key), index_(), kind_(kindKey) {} + +PathArgument::PathArgument(const JSONCPP_STRING& key) + : key_(key.c_str()), index_(), kind_(kindKey) {} + +// class Path +// ////////////////////////////////////////////////////////////////// + +Path::Path(const JSONCPP_STRING& path, + const PathArgument& a1, + const PathArgument& a2, + const PathArgument& a3, + const PathArgument& a4, + const PathArgument& a5) { + InArgs in; + in.reserve(5); + in.push_back(&a1); + in.push_back(&a2); + in.push_back(&a3); + in.push_back(&a4); + in.push_back(&a5); + makePath(path, in); +} + +void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) { + const char* current = path.c_str(); + const char* end = current + path.length(); + InArgs::const_iterator itInArg = in.begin(); + while (current != end) { + if (*current == '[') { + ++current; + if (*current == '%') + addPathInArg(path, in, itInArg, PathArgument::kindIndex); + else { + ArrayIndex index = 0; + for (; current != end && *current >= '0' && *current <= '9'; ++current) + index = index * 10 + ArrayIndex(*current - '0'); + args_.push_back(index); + } + if (current == end || *++current != ']') + invalidPath(path, int(current - path.c_str())); + } else if (*current == '%') { + addPathInArg(path, in, itInArg, PathArgument::kindKey); + ++current; + } else if (*current == '.' || *current == ']') { + ++current; + } else { + const char* beginName = current; + while (current != end && !strchr("[.", *current)) + ++current; + args_.push_back(JSONCPP_STRING(beginName, current)); + } + } +} + +void Path::addPathInArg(const JSONCPP_STRING& /*path*/, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind) { + if (itInArg == in.end()) { + // Error: missing argument %d + } else if ((*itInArg)->kind_ != kind) { + // Error: bad argument type + } else { + args_.push_back(**itInArg++); + } +} + +void Path::invalidPath(const JSONCPP_STRING& /*path*/, int /*location*/) { + // Error: invalid path. +} + +const Value& Path::resolve(const Value& root) const { + const Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray() || !node->isValidIndex(arg.index_)) { + // Error: unable to resolve path (array value expected at position... + return Value::null; + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: unable to resolve path (object value expected at position...) + return Value::null; + } + node = &((*node)[arg.key_]); + if (node == &Value::nullSingleton()) { + // Error: unable to resolve path (object has no member named '' at + // position...) + return Value::null; + } + } + } + return *node; +} + +Value Path::resolve(const Value& root, const Value& defaultValue) const { + const Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray() || !node->isValidIndex(arg.index_)) + return defaultValue; + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) + return defaultValue; + node = &((*node)[arg.key_]); + if (node == &Value::nullSingleton()) + return defaultValue; + } + } + return *node; +} + +Value& Path::make(Value& root) const { + Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray()) { + // Error: node is not an array at position ... + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: node is not an object at position... + } + node = &((*node)[arg.key_]); + } + } + return *node; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_value.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include "json_tool.h" +#include +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include +#include + +#if __cplusplus >= 201103L +#include +#include + +#if !defined(isnan) +#define isnan std::isnan +#endif + +#if !defined(isfinite) +#define isfinite std::isfinite +#endif + +#if !defined(snprintf) +#define snprintf std::snprintf +#endif +#else +#include +#include + +#if defined(_MSC_VER) +#if !defined(isnan) +#include +#define isnan _isnan +#endif + +#if !defined(isfinite) +#include +#define isfinite _finite +#endif + +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 +#if !defined(snprintf) +#define snprintf _snprintf +#endif +#endif + +#if defined(__sun) && defined(__SVR4) // Solaris +#if !defined(isfinite) +#include +#define isfinite finite +#endif +#endif + +#if defined(__hpux) +#if !defined(isfinite) +#if defined(__ia64) && !defined(finite) +#define isfinite(x) \ + ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x))) +#endif +#endif +#endif + +#if !defined(isnan) +// IEEE standard states that NaN values will not compare to themselves +#define isnan(x) (x != x) +#endif + +#if !defined(isfinite) +#define isfinite finite +#endif +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr StreamWriterPtr; +#else +typedef std::auto_ptr StreamWriterPtr; +#endif + +JSONCPP_STRING valueToString(LargestInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + if (value == Value::minLargestInt) { + uintToString(LargestUInt(Value::maxLargestInt) + 1, current); + *--current = '-'; + } else if (value < 0) { + uintToString(LargestUInt(-value), current); + *--current = '-'; + } else { + uintToString(LargestUInt(value), current); + } + assert(current >= buffer); + return current; +} + +JSONCPP_STRING valueToString(LargestUInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + uintToString(value, current); + assert(current >= buffer); + return current; +} + +#if defined(JSON_HAS_INT64) + +JSONCPP_STRING valueToString(Int value) { + return valueToString(LargestInt(value)); +} + +JSONCPP_STRING valueToString(UInt value) { + return valueToString(LargestUInt(value)); +} + +#endif // # if defined(JSON_HAS_INT64) + +namespace { +JSONCPP_STRING valueToString(double value, + bool useSpecialFloats, + unsigned int precision, + PrecisionType precisionType) { + // Print into the buffer. We need not request the alternative representation + // that always has a decimal point because JSON doesn't distinguish the + // concepts of reals and integers. + if (!isfinite(value)) { + static const char* const reps[2][3] = { { "NaN", "-Infinity", "Infinity" }, + { "null", "-1e+9999", "1e+9999" } }; + return reps[useSpecialFloats ? 0 : 1] + [isnan(value) ? 0 : (value < 0) ? 1 : 2]; + } + + JSONCPP_STRING buffer(size_t(36), '\0'); + while (true) { + int len = snprintf( + &*buffer.begin(), buffer.size(), + (precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f", + precision, value); + assert(len >= 0); + size_t wouldPrint = static_cast(len); + if (wouldPrint >= buffer.size()) { + buffer.resize(wouldPrint + 1); + continue; + } + buffer.resize(wouldPrint); + break; + } + + buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end()); + + // strip the zero padding from the right + if (precisionType == PrecisionType::decimalPlaces) { + buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end()); + } + + // try to ensure we preserve the fact that this was given to us as a double on + // input + if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) { + buffer += ".0"; + } + return buffer; +} +} // namespace + +JSONCPP_STRING valueToString(double value, + unsigned int precision, + PrecisionType precisionType) { + return valueToString(value, false, precision, precisionType); +} + +JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; } + +static bool isAnyCharRequiredQuoting(char const* s, size_t n) { + assert(s || !n); + + char const* const end = s + n; + for (char const* cur = s; cur < end; ++cur) { + if (*cur == '\\' || *cur == '\"' || *cur < ' ' || + static_cast(*cur) < 0x80) + return true; + } + return false; +} + +static unsigned int utf8ToCodepoint(const char*& s, const char* e) { + const unsigned int REPLACEMENT_CHARACTER = 0xFFFD; + + unsigned int firstByte = static_cast(*s); + + if (firstByte < 0x80) + return firstByte; + + if (firstByte < 0xE0) { + if (e - s < 2) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = + ((firstByte & 0x1F) << 6) | (static_cast(s[1]) & 0x3F); + s += 1; + // oversized encoded characters are invalid + return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated; + } + + if (firstByte < 0xF0) { + if (e - s < 3) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = ((firstByte & 0x0F) << 12) | + ((static_cast(s[1]) & 0x3F) << 6) | + (static_cast(s[2]) & 0x3F); + s += 2; + // surrogates aren't valid codepoints itself + // shouldn't be UTF-8 encoded + if (calculated >= 0xD800 && calculated <= 0xDFFF) + return REPLACEMENT_CHARACTER; + // oversized encoded characters are invalid + return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated; + } + + if (firstByte < 0xF8) { + if (e - s < 4) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = ((firstByte & 0x07) << 18) | + ((static_cast(s[1]) & 0x3F) << 12) | + ((static_cast(s[2]) & 0x3F) << 6) | + (static_cast(s[3]) & 0x3F); + s += 3; + // oversized encoded characters are invalid + return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated; + } + + return REPLACEMENT_CHARACTER; +} + +static const char hex2[] = "000102030405060708090a0b0c0d0e0f" + "101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f" + "505152535455565758595a5b5c5d5e5f" + "606162636465666768696a6b6c6d6e6f" + "707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; + +static JSONCPP_STRING toHex16Bit(unsigned int x) { + const unsigned int hi = (x >> 8) & 0xff; + const unsigned int lo = x & 0xff; + JSONCPP_STRING result(4, ' '); + result[0] = hex2[2 * hi]; + result[1] = hex2[2 * hi + 1]; + result[2] = hex2[2 * lo]; + result[3] = hex2[2 * lo + 1]; + return result; +} + +static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { + if (value == NULL) + return ""; + + if (!isAnyCharRequiredQuoting(value, length)) + return JSONCPP_STRING("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + JSONCPP_STRING::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL + JSONCPP_STRING result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + char const* end = value + length; + for (const char* c = value; c != end; ++c) { + switch (*c) { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + // case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something.) + // blep notes: actually escaping \/ may be useful in javascript to avoid = 0x20) + result += static_cast(cp); + else if (cp < 0x10000) { // codepoint is in Basic Multilingual Plane + result += "\\u"; + result += toHex16Bit(cp); + } else { // codepoint is not in Basic Multilingual Plane + // convert to surrogate pair first + cp -= 0x10000; + result += "\\u"; + result += toHex16Bit((cp >> 10) + 0xD800); + result += "\\u"; + result += toHex16Bit((cp & 0x3FF) + 0xDC00); + } + } break; + //default: { + // result += *c; + //}break; + //xwj --------------- + } + } + result += "\""; + return result; +} + +JSONCPP_STRING valueToQuotedString(const char* value) { + return valueToQuotedStringN(value, static_cast(strlen(value))); +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() {} + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + : yamlCompatibilityEnabled_(false), dropNullPlaceholders_(false), + omitEndingLineFeed_(false) {} + +void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; } + +void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } + +void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } + +JSONCPP_STRING FastWriter::write(const Value& root) { + document_.clear(); + writeValue(root); + if (!omitEndingLineFeed_) + document_ += '\n'; + return document_; +} + +void FastWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + if (!dropNullPlaceholders_) + document_ += "null"; + break; + case intValue: + document_ += valueToString(value.asLargestInt()); + break; + case uintValue: + document_ += valueToString(value.asLargestUInt()); + break; + case realValue: + document_ += valueToString(value.asDouble()); + break; + case stringValue: { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) + document_ += valueToQuotedStringN(str, static_cast(end - str)); + break; + } + case booleanValue: + document_ += valueToString(value.asBool()); + break; + case arrayValue: { + document_ += '['; + ArrayIndex size = value.size(); + for (ArrayIndex index = 0; index < size; ++index) { + if (index > 0) + document_ += ','; + writeValue(value[index]); + } + document_ += ']'; + } break; + case objectValue: { + Value::Members members(value.getMemberNames()); + document_ += '{'; + for (Value::Members::iterator it = members.begin(); it != members.end(); + ++it) { + const JSONCPP_STRING& name = *it; + if (it != members.begin()) + document_ += ','; + document_ += valueToQuotedStringN(name.data(), + static_cast(name.length())); + document_ += yamlCompatibilityEnabled_ ? ": " : ":"; + writeValue(value[name]); + } + document_ += '}'; + } break; + } +} + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() + : rightMargin_(74), indentSize_(3), addChildValues_() {} + +JSONCPP_STRING StyledWriter::write(const Value& root) { + document_.clear(); + addChildValues_ = false; + indentString_.clear(); + writeCommentBeforeValue(root); + writeValue(root); + writeCommentAfterValueOnSameLine(root); + document_ += '\n'; + return document_; +} + +void StyledWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast(end - str))); + else + pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + const JSONCPP_STRING& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + document_ += " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultilineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + writeIndent(); + writeValue(childValue); + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + document_ += "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + document_ += ", "; + document_ += childValues_[index]; + } + document_ += " ]"; + } + } +} + +bool StyledWriter::isMultilineArray(const Value& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledWriter::pushValue(const JSONCPP_STRING& value) { + if (addChildValues_) + childValues_.push_back(value); + else + document_ += value; +} + +void StyledWriter::writeIndent() { + if (!document_.empty()) { + char last = document_[document_.length() - 1]; + if (last == ' ') // already indented + return; + if (last != '\n') // Comments may add new-line + document_ += '\n'; + } + document_ += indentString_; +} + +void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) { + writeIndent(); + document_ += value; +} + +void StyledWriter::indent() { + indentString_ += JSONCPP_STRING(indentSize_, ' '); +} + +void StyledWriter::unindent() { + assert(indentString_.size() >= indentSize_); + indentString_.resize(indentString_.size() - indentSize_); +} + +void StyledWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + document_ += '\n'; + writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + document_ += *iter; + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) + writeIndent(); + ++iter; + } + + // Comments are stripped of trailing newlines, so add one here + document_ += '\n'; +} + +void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + document_ += " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + document_ += '\n'; + document_ += root.getComment(commentAfter); + document_ += '\n'; + } +} + +bool StyledWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter(const JSONCPP_STRING& indentation) + : document_(NULL), rightMargin_(74), indentation_(indentation), + addChildValues_(), indented_(false) {} + +void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) { + document_ = &out; + addChildValues_ = false; + indentString_.clear(); + indented_ = true; + writeCommentBeforeValue(root); + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *document_ << "\n"; + document_ = NULL; // Forget the stream, for safety. +} + +void StyledStreamWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast(end - str))); + else + pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + const JSONCPP_STRING& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + *document_ << " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledStreamWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultilineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *document_ << "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *document_ << ", "; + *document_ << childValues_[index]; + } + *document_ << " ]"; + } + } +} + +bool StyledStreamWriter::isMultilineArray(const Value& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *document_ << value; +} + +void StyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + *document_ << '\n' << indentString_; +} + +void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) { + if (!indented_) + writeIndent(); + *document_ << value; + indented_ = false; +} + +void StyledStreamWriter::indent() { indentString_ += indentation_; } + +void StyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) + writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *document_ << *iter; + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would include newline + *document_ << indentString_; + ++iter; + } + indented_ = false; +} + +void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + *document_ << ' ' << root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *document_ << root.getComment(commentAfter); + } + indented_ = false; +} + +bool StyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +////////////////////////// +// BuiltStyledStreamWriter + +/// Scoped enums are not available until C++11. +struct CommentStyle { + /// Decide whether to write comments. + enum Enum { + None, ///< Drop all comments. + Most, ///< Recover odd behavior of previous versions (not implemented yet). + All ///< Keep all comments. + }; +}; + +struct BuiltStyledStreamWriter : public StreamWriter { + BuiltStyledStreamWriter(JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision, + PrecisionType precisionType); + int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE; + +private: + void writeValue(Value const& value); + void writeArrayValue(Value const& value); + bool isMultilineArray(Value const& value); + void pushValue(JSONCPP_STRING const& value); + void writeIndent(); + void writeWithIndent(JSONCPP_STRING const& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(Value const& root); + void writeCommentAfterValueOnSameLine(Value const& root); + static bool hasCommentForValue(const Value& value); + + typedef std::vector ChildValues; + + ChildValues childValues_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; + CommentStyle::Enum cs_; + JSONCPP_STRING colonSymbol_; + JSONCPP_STRING nullSymbol_; + JSONCPP_STRING endingLineFeedSymbol_; + bool addChildValues_ : 1; + bool indented_ : 1; + bool useSpecialFloats_ : 1; + unsigned int precision_; + PrecisionType precisionType_; +}; +BuiltStyledStreamWriter::BuiltStyledStreamWriter( + JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision, + PrecisionType precisionType) + : rightMargin_(74), indentation_(indentation), cs_(cs), + colonSymbol_(colonSymbol), nullSymbol_(nullSymbol), + endingLineFeedSymbol_(endingLineFeedSymbol), addChildValues_(false), + indented_(false), useSpecialFloats_(useSpecialFloats), + precision_(precision), precisionType_(precisionType) {} +int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout) { + sout_ = sout; + addChildValues_ = false; + indented_ = true; + indentString_.clear(); + writeCommentBeforeValue(root); + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *sout_ << endingLineFeedSymbol_; + sout_ = NULL; + return 0; +} +void BuiltStyledStreamWriter::writeValue(Value const& value) { + switch (value.type()) { + case nullValue: + pushValue(nullSymbol_); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_, + precisionType_)); + break; + case stringValue: { + // Is NULL is possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast(end - str))); + else + pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + JSONCPP_STRING const& name = *it; + Value const& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedStringN( + name.data(), static_cast(name.length()))); + *sout_ << colonSymbol_; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value); + if (isMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + Value const& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *sout_ << "["; + if (!indentation_.empty()) + *sout_ << " "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *sout_ << ((!indentation_.empty()) ? ", " : ","); + *sout_ << childValues_[index]; + } + if (!indentation_.empty()) + *sout_ << " "; + *sout_ << "]"; + } + } +} + +bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + Value const& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *sout_ << value; +} + +void BuiltStyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + + if (!indentation_.empty()) { + // In this case, drop newlines too. + *sout_ << '\n' << indentString_; + } +} + +void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) { + if (!indented_) + writeIndent(); + *sout_ << value; + indented_ = false; +} + +void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } + +void BuiltStyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { + if (cs_ == CommentStyle::None) + return; + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) + writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *sout_ << *iter; + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would write extra newline + *sout_ << indentString_; + ++iter; + } + indented_ = false; +} + +void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine( + Value const& root) { + if (cs_ == CommentStyle::None) + return; + if (root.hasComment(commentAfterOnSameLine)) + *sout_ << " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *sout_ << root.getComment(commentAfter); + } +} + +// static +bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +/////////////// +// StreamWriter + +StreamWriter::StreamWriter() : sout_(NULL) {} +StreamWriter::~StreamWriter() {} +StreamWriter::Factory::~Factory() {} +StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); } +StreamWriterBuilder::~StreamWriterBuilder() {} +StreamWriter* StreamWriterBuilder::newStreamWriter() const { + JSONCPP_STRING indentation = settings_["indentation"].asString(); + JSONCPP_STRING cs_str = settings_["commentStyle"].asString(); + JSONCPP_STRING pt_str = settings_["precisionType"].asString(); + bool eyc = settings_["enableYAMLCompatibility"].asBool(); + bool dnp = settings_["dropNullPlaceholders"].asBool(); + bool usf = settings_["useSpecialFloats"].asBool(); + unsigned int pre = settings_["precision"].asUInt(); + CommentStyle::Enum cs = CommentStyle::All; + if (cs_str == "All") { + cs = CommentStyle::All; + } else if (cs_str == "None") { + cs = CommentStyle::None; + } else { + throwRuntimeError("commentStyle must be 'All' or 'None'"); + } + PrecisionType precisionType(significantDigits); + if (pt_str == "significant") { + precisionType = PrecisionType::significantDigits; + } else if (pt_str == "decimal") { + precisionType = PrecisionType::decimalPlaces; + } else { + throwRuntimeError("precisionType must be 'significant' or 'decimal'"); + } + JSONCPP_STRING colonSymbol = " : "; + if (eyc) { + colonSymbol = ": "; + } else if (indentation.empty()) { + colonSymbol = ":"; + } + JSONCPP_STRING nullSymbol = "null"; + if (dnp) { + nullSymbol.clear(); + } + if (pre > 17) + pre = 17; + JSONCPP_STRING endingLineFeedSymbol; + return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol, + endingLineFeedSymbol, usf, pre, + precisionType); +} +static void getValidWriterKeys(std::set* valid_keys) { + valid_keys->clear(); + valid_keys->insert("indentation"); + valid_keys->insert("commentStyle"); + valid_keys->insert("enableYAMLCompatibility"); + valid_keys->insert("dropNullPlaceholders"); + valid_keys->insert("useSpecialFloats"); + valid_keys->insert("precision"); + valid_keys->insert("precisionType"); +} +bool StreamWriterBuilder::validate(Json::Value* invalid) const { + Json::Value my_invalid; + if (!invalid) + invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set valid_keys; + getValidWriterKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + JSONCPP_STRING const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) { + return settings_[key]; +} +// static +void StreamWriterBuilder::setDefaults(Json::Value* settings) { + //! [StreamWriterBuilderDefaults] + (*settings)["commentStyle"] = "All"; + (*settings)["indentation"] = "\t"; + (*settings)["enableYAMLCompatibility"] = false; + (*settings)["dropNullPlaceholders"] = false; + (*settings)["useSpecialFloats"] = false; + (*settings)["precision"] = 17; + (*settings)["precisionType"] = "significant"; + //! [StreamWriterBuilderDefaults] +} + +JSONCPP_STRING writeString(StreamWriter::Factory const& factory, + Value const& root) { + JSONCPP_OSTRINGSTREAM sout; + StreamWriterPtr const writer(factory.newStreamWriter()); + writer->write(root, &sout); + return sout.str(); +} + +JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) { + StreamWriterBuilder builder; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + diff --git a/example/test_example.cpp b/example/test_example.cpp new file mode 100644 index 0000000..28dae2c --- /dev/null +++ b/example/test_example.cpp @@ -0,0 +1,170 @@ +#include +#include +#include +#include "deal.h" +#include +#include +#include +#include +void handler(int sig) +{ + printf("Get handler sig"); + string strcmd = "ps -ef | grep test_JBL_Check| awk '{print $2}' | xargs kill -9 "; + const char *cmd = strcmd.c_str(); + printf("delete test_JBL_Check success"); + if (-1 == system(cmd)) + { + std::cout << "error" << std::endl; + } + + // delete UnderCarriageCoreLogic::GetInstance(); + exit(0); +} + +int _sysmkdir(const std::string &dir) +{ + int ret = mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if (ret && errno == EEXIST) + { + // printf("dir[%s] already exist.\n", dir.c_str()); + } + else if (ret) + { + printf("create dir[%s] error: %d %s\n", dir.c_str(), ret, strerror(errno)); + return -1; + } + else + { + printf("create dir[%s] success.\n", dir.c_str()); + } + return 0; +} +std::string __getParentDir(const std::string &dir) +{ + std::string pdir = dir; + if (pdir.length() < 1 || (pdir[0] != '/')) + { + return ""; + } + while (pdir.length() > 1 && (pdir[pdir.length() - 1] == '/')) + pdir = pdir.substr(0, pdir.length() - 1); + + pdir = pdir.substr(0, pdir.find_last_of('/')); + return pdir; +} +int _sysmkdirs(const std::string &dir) +{ + int ret = 0; + if (dir.empty()) + return -1; + std::string pdir; + if ((ret = _sysmkdir(dir)) == -1) + { + pdir = __getParentDir(dir); + if ((ret = _sysmkdirs(pdir)) == 0) + { + ret = _sysmkdirs(dir); + } + } + + return ret; +} + +int main(int argc, char *argv[]) +{ + + deal test; + + if (argc > 1 && string(argv[1]) == "-h") + { + cout << "******************************************************" << endl; + cout << "*** 1、./test_JBL_Check: 默认处理一套图 图片文件夹位于 ../data/img/t1,结果位于/home/aidlux/BOE/testresult" << endl; + cout << "*** 2、./test_JBL_Check -s: 1 的基础上增加 过程存图,包括edge 和字符检测的中间结果存图,图片位于 当前文件夹。" << endl; + cout << "*** 3、./test_JBL_Check -fjc filepath: 处理精测套图大图 结果位于/home/aidlux/BOE/ResultImg" << endl; + cout << "*** 4、./test_JBL_Check -feai filepath num: 批量测试边缘检测算法,num 至多处理张数,结果:/home/aidlux/BOE/Edge" << endl; + cout << "*** 5、./test_JBL_Check -falign filepath num : 批量测试定位算法,num 至多处理张数,结果:/home/aidlux/BOE/Align" << endl; + cout << "*** 6、./test_JBL_Check -rjson filepath: 单张复测,filepath xx/xx/3A3K380001B1DK_20240408_152157_Main_0_2_L255" << endl; + cout << "*** 6、./test_JBL_Check -rjsonall filepath: 一套图复测,filepath xx/xx/" << endl; + + cout << "******************************************************" << endl; + return 0; + } + + printf("argc = %d\n", argc); + for (int i = 0; i < argc; i++) + { + printf("argv[%d]=%s\n", i, argv[i]); + } + + if (argc > 1 && string(argv[1]) != "-h") + { + + for (int i = 1; i < argc; i++) + { + if (string(argv[i]) == "-rs") + { + test.runConfig.run_Type = Process_Run_SaveImg; + } + else if (string(argv[i]) == "-rd") + { + test.runConfig.run_Type = Process_Run_Detect; + } + else if (string(argv[i]) == "-rjson") + { + if (i + 1 >= argc) + { + printf("error Not Path \n"); + return -1; + } + + test.runConfig.run_Type = Process_Run_ReJson; + test.runConfig.filePath = string(argv[i + 1]); + } + else if (string(argv[i]) == "-f" && i + 1 < argc) + { + test.runConfig.det_Type = RUNTYPE_RUN_File; + test.runConfig.filePath = string(argv[i + 1]); + } + else if (string(argv[i]) == "-fe" && i + 1 < argc) + { + test.runConfig.det_Type = RUNTYPE_RUN_EDGE_TEST; + test.runConfig.filePath = string(argv[i + 1]); + } + else if (string(argv[i]) == "-feai" && i + 1 < argc) + { + test.runConfig.det_Type = RUNTYPE_RUN_EDGE_TEST_AI; + test.runConfig.filePath = string(argv[i + 1]); + } + else if (string(argv[i]) == "-m") + { + test.runConfig.det_Type = RUNTYPE_RUN_Merge_Img; + } + if (string(argv[i]) == "-s") + { + test.runConfig.bSaveProcessImg = true; + } + if (string(argv[i]) == "-ud") + { + test.runConfig.bdecode = false; + } + if (string(argv[i]) == "-fud" && i + 1 < argc) + { + test.runConfig.det_Type = RUNTYPE_RUN_File; + test.runConfig.filePath = string(argv[i + 1]); + test.runConfig.bdecode = false; + } + } + } + + test.runConfig.print("config"); + // getchar(); + signal(SIGINT, handler); + test.start(); + + while (true) + { + usleep(10 * 1000); + } + + return 0; +}