#include "camera.h" #include // Debug Options #define GlobalDebug 1 #define DebugDetection 1 #define DebugLowerMacCOM 0 camera::camera() {} QTcpServer* server_to_lowermachine = nullptr; QTcpSocket* lower_machine = nullptr; bool volatile is_running = false; //编号0 RGB相机 编号1 BV相机 static MIL_ID MilApplication; static MIL_ID MilSystem; static MIL_ID MilDigitizer0; static MIL_ID MilImage0; static MIL_ID MilImage_Color0; static MIL_ID detection_result0; static MIL_ID MilImage_Onnx0; static MIL_ID ModifiedBufferId0; static MIL_ID MilGrabBufferList0[20] = {0}; static MIL_INT BufSizeX0 = 4096; static MIL_INT BufSizeY0 = 512; unsigned char* m_AvsBuffer0 = (unsigned char*)malloc(BufSizeX0 * BufSizeY0 * 3); static int FuncCount0 = 1; static MIL_ID MilDigitizer1; static MIL_ID MilImage1; static MIL_ID MilImage_Color1; static MIL_ID detection_result1; static MIL_ID MilImage_Onnx1; static MIL_ID ModifiedBufferId1; static MIL_ID MilGrabBufferList1[20] = {0}; static MIL_INT BufSizeX1 = 4096; static MIL_INT BufSizeY1 = 512; unsigned char* m_AvsBuffer1 = (unsigned char*)malloc(BufSizeX1 * BufSizeY1 * 3); static int FuncCount1 = 1; int SaveImg_Flag; ONNXRunner runner; std::map params; int widthBlocks = 20; int heightBlocks = 512; int sizeThreshold = 20; int padLeft = 1; int padRight = 1; int rowRange = 0; int ignoreSide=2; int skipLeftCols=10; int skipRightCols=10; static std::vector> tail_0(0); static std::vector> tail_1(0); uint8_t temp_buf[512 * 64] = {0}; extern int file_delay; extern int file_encoder; extern int file_valve; // ONNXRunner runner; bool iniCamera() { //分配application MappAlloc(M_DEFAULT, &MilApplication); //分配system MsysAlloc(M_DEFAULT, M_SYSTEM_RADIENTEVCL, M_DEV0, M_DEFAULT, &MilSystem); //分配相机 digitier MdigAlloc(MilSystem,M_DEV0,MIL_TEXT("C:/Users/Pc/Desktop/1.dcf"),M_DEFAULT,&MilDigitizer0); MdigAlloc(MilSystem,M_DEV1,MIL_TEXT("C:/Users/Pc/Desktop/2.dcf"),M_DEFAULT,&MilDigitizer1); //给MilImage分配空间 MbufAllocColor(MilSystem,3,BufSizeX0,BufSizeY0,8 + M_UNSIGNED,M_IMAGE + M_GRAB + M_PROC,&MilImage0); MbufAllocColor(MilSystem,3,BufSizeX1,BufSizeY1,8 + M_UNSIGNED,M_IMAGE + M_GRAB + M_PROC,&MilImage1); MbufAllocColor(MilSystem,3,BufSizeX0,BufSizeY0,8 + M_UNSIGNED,M_IMAGE + M_GRAB + M_PROC,&MilImage_Color0); MbufAllocColor(MilSystem,3,BufSizeX1,BufSizeY1,8 + M_UNSIGNED,M_IMAGE + M_GRAB + M_PROC,&MilImage_Color1); MbufAllocColor(MilSystem,3,BufSizeX0,BufSizeY0,8 + M_UNSIGNED,M_IMAGE + M_GRAB + M_PROC,&detection_result0); MbufAllocColor(MilSystem,3,BufSizeX1,BufSizeY1,8 + M_UNSIGNED,M_IMAGE + M_GRAB + M_PROC,&detection_result1); MbufAllocColor(MilSystem,3,BufSizeX0,BufSizeY0,8 + M_UNSIGNED,M_IMAGE + M_GRAB + M_PROC,&MilImage_Onnx0); MbufAllocColor(MilSystem,3,BufSizeX1,BufSizeY1,8 + M_UNSIGNED,M_IMAGE + M_GRAB + M_PROC,&MilImage_Onnx1); //给每一个bufferlist分配空间 for (int i = 0; i < 20; i++) { // 系统 3维度 宽 高 8位无符号 图像数据 对象 MbufAllocColor(MilSystem,3,BufSizeX0,BufSizeY0,8 + M_UNSIGNED,M_IMAGE + M_GRAB + M_PROC,&MilGrabBufferList0[i]); if (MilGrabBufferList0[i]) { MbufClear(MilGrabBufferList0[i], 0xFF); } else { break; } } for (int i = 0; i < 20; i++) { // 系统 3维度 宽 高 8位无符号 图像数据 对象 MbufAllocColor(MilSystem,3,BufSizeX1,BufSizeY1,8 + M_UNSIGNED,M_IMAGE + M_GRAB + M_PROC,&MilGrabBufferList1[i]); if (MilGrabBufferList1[i]) { MbufClear(MilGrabBufferList1[i], 0xFF); } else { break; } } qDebug()<<"ready"; return 1; } #if(GlobalDebug && DebugDetection) #define SAVE_PATH_resize MIL_TEXT ("C:\\Users\\Pc\\Desktop\\cotton_double2//resize.png") #define SAVE_PATH_flip MIL_TEXT ("C:\\Users\\Pc\\Desktop\\cotton_double2//flip.png") #define SAVE_PATH_raw MIL_TEXT ("C:\\Users\\Pc\\Desktop\\cotton_double2//raw.png") #define SAVE_PATH_result MIL_TEXT ("C:\\Users\\Pc\\Desktop\\cotton_double2//result.png") #endif MIL_INT ProcessingFunction0(MIL_INT HookType, MIL_ID HookId, void *HookDataPtr) { MdigGetHookInfo(HookId, M_MODIFIED_BUFFER + M_BUFFER_ID, &ModifiedBufferId0); if(SaveImg_Flag) { //拷贝存图图像 MbufCopy(ModifiedBufferId0,MilImage0); //Mil保存路径 QString MilImgPath = QString("C:/Users/Pc/Desktop/cotton_double2/Img1/%1.bmp").arg(FuncCount0); MIL_STRING MilImagePath = MilImgPath.toStdWString(); MbufExport(MilImagePath,M_BMP,MilImage0); qDebug()<<"回调1成功存储照片:"< result = runner.predict(image); // Img_Onnx = runner.postProcess(result, image); // std::vector> mask_Onnx1 = generateMaskFromImage2(Img_Onnx, widthBlocks, heightBlocks, sizeThreshold); // timer1.printElapsedTime("onnx sat finished"); // timer1.restart(); auto [mask_1, newTail] = generateMaskWithTail(detection_result0, tail_1, widthBlocks, heightBlocks, sizeThreshold, rowRange, skipLeftCols, skipRightCols); tail_1 = newTail; // timer1.printElapsedTime("tail finished"); // timer1.restart(); // std::vector> mask_Color1 = generateMaskFromImage(detection_result1, widthBlocks, heightBlocks, thresholds); PadColumns(mask_1,padLeft,padRight,0); std::vector> mask_Total = expandArray(mask_1,64); // timer1.printElapsedTime("expand finished"); // for(int m = 0 ; m < 512 ; m ++) // { // for(int n = 0; n < 22 ; n++) // { // if(mask_Total[m][n] == 1) // { // for(int k = 0; k < 50; k++) // { // mask_Total[m + k][n] = 1; // } // } // } // } // save masks vector> mask = generateMask(detection_result0, widthBlocks, heightBlocks, sizeThreshold,skipLeftCols, skipRightCols); #if(GlobalDebug && DebugDetection) VectorToImg(mask,"C:/Users/Pc/Desktop/img/mask" + std::to_string(FuncCount1) + ".bmp"); VectorToImg(mask_1,"C:/Users/Pc/Desktop/img/mask_ignored" + std::to_string(FuncCount1) + ".bmp"); VectorToImg(mask_Total,"C:/Users/Pc/Desktop/img/mask_expended" + std::to_string(FuncCount1) + ".bmp"); #endif bool result_Low = get_valve_data(mask_Total); if(!result_Low) { qDebug()<<"下位机发送失败"; } return 0; } Timer timer2; MIL_INT ProcessingFunction1(MIL_INT HookType, MIL_ID HookId, void *HookDataPtr) { FuncCount1++; MdigGetHookInfo(HookId, M_MODIFIED_BUFFER + M_BUFFER_ID, &ModifiedBufferId1); if(SaveImg_Flag) { //拷贝存图数据 MbufCopy(ModifiedBufferId1,MilImage1); //Mil保存路径 QString MilImgPath = QString("C:/Users/Pc/Desktop/cotton_double2/Img2/%1.bmp").arg(FuncCount1); MIL_STRING MilImagePath = MilImgPath.toStdWString(); MbufExport(MilImagePath,M_BMP,MilImage1); qDebug()<<"回调2成功存储照片:"< result = runner.predict(image); // // Img_Onnx = runner.postProcess(result, image); // // std::vector> mask_Onnx1 = generateMaskFromImage2(Img_Onnx, widthBlocks, heightBlocks, sizeThreshold); // // timer1.printElapsedTime("onnx sat finished"); // // timer1.restart(); // auto [mask_1, newTail] = generateMaskWithTail(detection_result1, tail_1, widthBlocks, heightBlocks, sizeThreshold, rowRange); // tail_1 = newTail; // // timer1.printElapsedTime("tail finished"); // // timer1.restart(); // // std::vector> mask_Color1 = generateMaskFromImage(detection_result1, widthBlocks, heightBlocks, thresholds); // std::vector> mask_Total = expandArray(mask_1,64); // // timer1.printElapsedTime("expand finished"); // // for(int m = 0 ; m < 512 ; m ++) // // { // // for(int n = 0; n < 22 ; n++) // // { // // if(mask_Color1[m][n] == 1) // // { // // for(int k = 0; k < 50; k++) // // { // // mask_Total[m + k][n] = 1; // // } // // } // // } // // } // // VectorToImg(mask_Total,"C:/Users/admin/Desktop/maskImg/mask" + std::to_string(FuncCount1) + ".bmp"); // bool result_Low = get_valve_data(mask_Total); // if(!result_Low) // { // qDebug()<<"下位机发送失败"; // } // if(FuncCount1 == 2) // { // timer2.restart(); // } // if(FuncCount1 == 3) // { // timer2.printElapsedTime("send interval"); // } return 0; } bool DestoryCamera() { MdigProcess(MilDigitizer0, MilGrabBufferList0, 20, M_STOP, M_DEFAULT,ProcessingFunction0, M_NULL); MdigProcess(MilDigitizer1, MilGrabBufferList1, 20, M_STOP, M_DEFAULT,ProcessingFunction1, M_NULL); for (int i = 0; i < 20; i++) { MbufFree(MilGrabBufferList0[i]); } for (int i = 0; i < 20; i++) { MbufFree(MilGrabBufferList1[i]); } MbufFree(MilImage0); MbufFree(MilImage1); MbufFree(MilImage_Color0); MbufFree(MilImage_Color1); MbufFree(MilImage_Onnx0); MbufFree(MilImage_Onnx1); MbufFree(detection_result0); MbufFree(detection_result1); MdigFree(MilDigitizer0); MdigFree(MilDigitizer1); MsysFree(MilSystem); MappFree(MilApplication); return 1; } // Optimized LabProcess function void lab_process_raw(const MIL_ID& inputImage, MIL_ID& outputImageLab, const std::map& params, const std::vector& color_vector) { MIL_ID MilLabImage = M_NULL, MilLChannel = M_NULL, MilAChannel = M_NULL, MilBChannel = M_NULL; MIL_ID lab_result=M_NULL; int denoising = params.at("lab_denoising"); // Check number of bands MIL_INT NumBands = 0; MbufInquire(inputImage, M_SIZE_BAND, &NumBands); if (NumBands != 3) { printf("输入图像不是 3 通道图像,请提供彩色图像。\n"); return; } // Inquire image properties once MIL_ID MilSystem = MbufInquire(inputImage, M_OWNER_SYSTEM, M_NULL); MIL_INT SizeX = MbufInquire(inputImage, M_SIZE_X, M_NULL); MIL_INT SizeY = MbufInquire(inputImage, M_SIZE_Y, M_NULL); // Allocate buffer for Lab image MbufAllocColor(MilSystem, 3, SizeX, SizeY, 8 + M_UNSIGNED, M_IMAGE + M_PROC, &MilLabImage); // Convert image from sRGB to Lab MimConvert(inputImage, MilLabImage, M_SRGB_TO_LAB); // Create child buffers for L, a, b channels MbufChildColor(MilLabImage, 0, &MilLChannel); MbufChildColor(MilLabImage, 1, &MilAChannel); MbufChildColor(MilLabImage, 2, &MilBChannel); // Allocate output image as 1-bit image MbufAlloc2d(MilSystem, SizeX, SizeY, 8 + M_UNSIGNED, M_IMAGE + M_PROC, &outputImageLab); MbufClear(outputImageLab, 0); // Initialize to 0 // Pre-allocate binary buffers as 1-bit images MIL_ID MilBinaryL = M_NULL, MilBinaryA = M_NULL, MilBinaryB = M_NULL, MilResultLab = M_NULL; MbufAlloc2d(MilSystem, SizeX, SizeY, 8 + M_UNSIGNED, M_IMAGE + M_PROC, &MilBinaryL); MbufAlloc2d(MilSystem, SizeX, SizeY, 8 + M_UNSIGNED, M_IMAGE + M_PROC, &MilBinaryA); MbufAlloc2d(MilSystem, SizeX, SizeY, 8 + M_UNSIGNED, M_IMAGE + M_PROC, &MilBinaryB); MbufAlloc2d(MilSystem, SizeX, SizeY, 8 + M_UNSIGNED, M_IMAGE + M_PROC, &MilResultLab); MbufAlloc2d(MilSystem, SizeX, SizeY, 8 + M_UNSIGNED, M_IMAGE + M_PROC, &lab_result); // Iterate over colors // 遍历颜色 for (const auto& color : color_vector) { // 构建参数键 std::string L_min_key = color + "_L_min"; std::string L_max_key = color + "_L_max"; std::string a_min_key = color + "_a_min"; std::string a_max_key = color + "_a_max"; std::string b_min_key = color + "_b_min"; std::string b_max_key = color + "_b_max"; // 获取参数值 int L_min = params.at(L_min_key); int L_max = params.at(L_max_key); int a_min = params.at(a_min_key); int a_max = params.at(a_max_key); int b_min = params.at(b_min_key); int b_max = params.at(b_max_key); std::vector lab_min_ps = {L_min, a_min, b_min}; std::vector lab_max_ps = {L_max, a_max, b_max}; std::vector lab_min_cv = psLabToOpenCVLab(lab_min_ps); std::vector lab_max_cv = psLabToOpenCVLab(lab_max_ps); L_min = lab_min_cv[0]; L_max = lab_max_cv[0]; a_min = lab_min_cv[1]; a_max = lab_max_cv[1]; b_min = lab_min_cv[2]; b_max = lab_max_cv[2]; // 对每个通道进行二值化 MimBinarize(MilLChannel, MilBinaryL, M_IN_RANGE, L_min, L_max); MimBinarize(MilAChannel, MilBinaryA, M_IN_RANGE, a_min, a_max); MimBinarize(MilBChannel, MilBinaryB, M_IN_RANGE, b_min, b_max); // 合并阈值结果 MimArith(MilBinaryL, MilBinaryA, MilResultLab, M_AND); MimArith(MilResultLab, MilBinaryB, MilResultLab, M_AND); // 与输出图像合并 MimArith(lab_result, MilResultLab, lab_result, M_OR); } MimClose(lab_result, MilResultLab, denoising, M_BINARY); MimOpen(MilResultLab, outputImageLab, denoising, M_BINARY); // Free binary buffers MbufFree(MilBinaryL); MbufFree(MilBinaryA); MbufFree(MilBinaryB); MbufFree(MilResultLab); // Free resources MbufFree(MilLChannel); MbufFree(MilAChannel); MbufFree(MilBChannel); MbufFree(MilLabImage); MbufFree(lab_result); } void lab_process(const MIL_ID& inputImage, MIL_ID& outputImageLab, const std::map& params) { const std::vector colors = {"green", "blue", "orange", "black", "red", "purple"}; lab_process_raw(inputImage, outputImageLab, params, colors); } vector psLabToOpenCVLab(const vector& lab_ps) { int l_ps = lab_ps[0]; int a_ps = lab_ps[1]; int b_ps = lab_ps[2]; // Conversion formulas int l_cv = round((l_ps / 100.0) * 255.0); // Scale L from 0-100 to 0-255 int a_cv = round(((a_ps + 128.0) / 255.0) * 255.0); // Shift and scale a int b_cv = round(((b_ps + 128.0) / 255.0) * 255.0); // Shift and scale b return {l_cv, a_cv, b_cv}; } vector opencvLabToPsLab(const vector& lab_cv) { int l_cv = lab_cv[0]; int a_cv = lab_cv[1]; int b_cv = lab_cv[2]; // Conversion formulas int l_ps = round((l_cv / 255.0) * 100.0); // Scale L from 0-255 to 0-100 int a_ps = round((a_cv / 255.0) * 255.0 - 128.0); // Scale and shift a int b_ps = round((b_cv / 255.0) * 255.0 - 128.0); // Scale and shift b return {l_ps, a_ps, b_ps}; } void hsv_process(const MIL_ID& inputImage, MIL_ID& outputImageHSV, const std::map& params) { MIL_ID MilHSVImage = M_NULL, MilHChannel = M_NULL, MilSChannel = M_NULL, MilVChannel = M_NULL; MIL_ID hsv_result = M_NULL; MIL_ID hsv_denoising = M_NULL; int saturationThreshold = params.at("saturation_threshold"); int denoising = params.at("saturation_denoising"); // 检查输入图像的通道数 MIL_INT NumBands = 0; MbufInquire(inputImage, M_SIZE_BAND, &NumBands); if (NumBands != 3) { printf("输入图像不是 3 通道图像,请提供彩色图像。\n"); return; } // 分配用于存储 HSV 图像的缓冲区 MbufAllocColor(MbufInquire(inputImage, M_OWNER_SYSTEM, M_NULL), 3, MbufInquire(inputImage, M_SIZE_X, M_NULL), MbufInquire(inputImage, M_SIZE_Y, M_NULL), 8 + M_UNSIGNED, M_IMAGE + M_PROC + M_DISP, &MilHSVImage); // 将图像从 sRGB 转换到 HSV MimConvert(inputImage, MilHSVImage, M_RGB_TO_HSV); // 创建 HSV 通道的子缓冲区 MbufChildColor(MilHSVImage, 0, &MilHChannel); MbufChildColor(MilHSVImage, 1, &MilSChannel); MbufChildColor(MilHSVImage, 2, &MilVChannel); // 分配输出图像缓冲区 MbufAlloc2d(MilSystem, MbufInquire(inputImage, M_SIZE_X, M_NULL), MbufInquire(inputImage, M_SIZE_Y, M_NULL), 8 + M_UNSIGNED, M_IMAGE + M_PROC + M_DISP, &hsv_result); MbufAlloc2d(MilSystem, MbufInquire(inputImage, M_SIZE_X, M_NULL), MbufInquire(inputImage, M_SIZE_Y, M_NULL), 8 + M_UNSIGNED, M_IMAGE + M_PROC + M_DISP, &hsv_denoising); MbufAlloc2d(MilSystem, MbufInquire(inputImage, M_SIZE_X, M_NULL), MbufInquire(inputImage, M_SIZE_Y, M_NULL), 8 + M_UNSIGNED, M_IMAGE + M_PROC + M_DISP, &outputImageHSV); // 对 S 通道进行阈值分割 MimBinarize(MilSChannel, hsv_result, M_GREATER, saturationThreshold, M_NULL); MimClose(hsv_result, hsv_denoising, denoising, M_BINARY); MimOpen(hsv_denoising, outputImageHSV, denoising, M_BINARY); // 释放资源 MbufFree(MilHChannel); MbufFree(MilSChannel); MbufFree(MilVChannel); MbufFree(MilHSVImage); MbufFree(hsv_result); MbufFree(hsv_denoising); } void high_sat_detect(const MIL_ID& inputImage, MIL_ID& outputImage, const std::map& params) { MIL_ID output_hsv=M_NULL, output_lab=M_NULL; hsv_process(inputImage, output_hsv, params); lab_process(inputImage, output_lab, params); MbufAlloc2d(MilSystem, MbufInquire(inputImage, M_SIZE_X, M_NULL), MbufInquire(inputImage, M_SIZE_Y, M_NULL), 8 + M_UNSIGNED, M_IMAGE + M_PROC, &outputImage); // 合并 Lab 和 HSV 的结果(取“或”运算) MimArith(output_hsv, output_lab, outputImage, M_OR); MbufFree(output_lab); MbufFree(output_hsv); } void read_params_from_file(const std::string& filename, std::map& params) { std::ifstream infile(filename); if (!infile) { std::cerr << "无法打开文件: " << filename << std::endl; return; } std::string line; while (std::getline(infile, line)) { // 去除行首和行尾的空白字符 line.erase(0, line.find_first_not_of(" \t\r\n")); line.erase(line.find_last_not_of(" \t\r\n") + 1); // 跳过空行和注释行 if (line.empty() || line[0] == '#') continue; // 查找等号的位置 size_t pos = line.find('='); if (pos == std::string::npos) continue; // 如果没有等号,跳过该行 // 分割键和值,并去除空白字符 std::string key = line.substr(0, pos); std::string value_str = line.substr(pos + 1); key.erase(0, key.find_first_not_of(" \t")); key.erase(key.find_last_not_of(" \t") + 1); value_str.erase(0, value_str.find_first_not_of(" \t")); value_str.erase(value_str.find_last_not_of(" \t") + 1); // 将字符串转换为整数 int value; std::istringstream iss(value_str); if (!(iss >> value)) { std::cerr << "键 " << key << " 的值无效: " << value_str << std::endl; continue; } // 将键值对添加到参数映射中 params[key] = value; } } std::vector> generateMaskFromImage(const MIL_ID& inputImage, int widthBlocks, int heightBlocks, int thresholds= 10) { // 读取图像 // cv::Mat image = cv::imread(imagePath, cv::IMREAD_GRAYSCALE); // // 检查图像是否成功读取 // if (image.empty()) { // std::cerr << "无法加载图像,请检查路径是否正确: " << imagePath << std::endl; // exit(EXIT_FAILURE); // } cv::Mat image=mil2mat(inputImage); // 确保图像是二值化的 cv::threshold(image, image, 128, 255, cv::THRESH_BINARY); // 获取图像的宽度和高度 int imageWidth = image.cols; int imageHeight = image.rows; // 计算每个块的宽度和高度 int blockWidth = imageWidth / widthBlocks; int blockHeight = imageHeight / heightBlocks; // 创建掩膜矩阵 std::vector> mask_1(heightBlocks, std::vector(widthBlocks, false)); // 遍历每个块并统计白色像素点的数量 for (int i = 0; i < heightBlocks; ++i) { for (int j = 0; j < widthBlocks; ++j) { // 计算块的起始和结束位置 int x_start = j * blockWidth; int y_start = i * blockHeight; int x_end = (j == widthBlocks - 1) ? imageWidth : (j + 1) * blockWidth; int y_end = (i == heightBlocks - 1) ? imageHeight : (i + 1) * blockHeight; // 提取当前块 cv::Mat block = image(cv::Rect(x_start, y_start, x_end - x_start, y_end - y_start)); // 统计块中白色像素的数量 int whitePixelCount = cv::countNonZero(block); // 如果白色像素数大于阈值,将该块标记为 true if (whitePixelCount > thresholds) { mask_1[i][j] = true; } } } return mask_1; } std::vector> generateMaskFromImage2(const cv::Mat& image, int widthBlocks, int heightBlocks, int thresholds= 10) { // 确保图像是二值化的-* cv::threshold(image, image, 128, 255, cv::THRESH_BINARY); // 获取图像的宽度和高度 int imageWidth = image.cols; int imageHeight = image.rows; // 计算每个块的宽度和高度 int blockWidth = imageWidth / widthBlocks; int blockHeight = imageHeight / heightBlocks; // 创建掩膜矩阵 std::vector> mask(heightBlocks, std::vector(widthBlocks, false)); // 遍历每个块并统计白色像素点的数量 for (int i = 0; i < heightBlocks; ++i) { for (int j = 0; j < widthBlocks; ++j) { // 计算块的起始和结束位置 int x_start = j * blockWidth; int y_start = i * blockHeight; int x_end = (j == widthBlocks - 1) ? imageWidth : (j + 1) * blockWidth; int y_end = (i == heightBlocks - 1) ? imageHeight : (i + 1) * blockHeight; // 提取当前块 cv::Mat block = image(cv::Rect(x_start, y_start, x_end - x_start, y_end - y_start)); // 统计块中白色像素的数量 int whitePixelCount = cv::countNonZero(block); // 如果白色像素数大于阈值,将该块标记为 true if (whitePixelCount > thresholds) { mask[i][j] = true; } } } return mask; } void convert_to_uint8(const MIL_ID& input_img, MIL_ID& output_img) { MIL_INT size_x = MbufInquire(input_img, M_SIZE_X, M_NULL); MIL_INT size_y = MbufInquire(input_img, M_SIZE_Y, M_NULL); MIL_INT channel_num = MbufInquire(input_img, M_SIZE_BAND, M_NULL); MbufAlloc2d(MilSystem, size_x, size_y, 8 + M_UNSIGNED, M_IMAGE + M_PROC + M_DISP, &output_img); if(channel_num == 1) { MimArith(output_img, input_img, output_img, M_ADD); MimArith(output_img, 255.0, output_img, M_MULT_CONST); } else if(channel_num == 3) { MimConvert(input_img, output_img, M_RGB_TO_L); MimArith(output_img, M_NULL, output_img, M_NOT); } else { cout << "Unsupported channel number!" << endl; } } Mat mil2mat(const MIL_ID mil_img) { // 获取 MIL 图像的宽度、高度和通道数 MIL_INT width, height, channels, bitDepth; MbufInquire(mil_img, M_SIZE_X, &width); MbufInquire(mil_img, M_SIZE_Y, &height); MbufInquire(mil_img, M_SIZE_BAND, &channels); MbufInquire(mil_img, M_SIZE_BIT, &bitDepth); if (channels == 1) { // 单通道图像,直接读取整个缓冲区 Mat grayImage(height, width, CV_8UC1); if (bitDepth == 1) { MIL_ID temp_img; convert_to_uint8(mil_img, temp_img); MbufGet(temp_img, grayImage.data); MbufFree(temp_img); } else { MbufGet(mil_img, grayImage.data); } return grayImage; } if (channels == 3) { // 多通道图像,分通道读取 MIL_ID redChannel, greenChannel, blueChannel; MbufAlloc2d(M_DEFAULT, width, height, 8 + M_UNSIGNED, M_IMAGE + M_PROC, &redChannel); MbufAlloc2d(M_DEFAULT, width, height, 8 + M_UNSIGNED, M_IMAGE + M_PROC, &greenChannel); MbufAlloc2d(M_DEFAULT, width, height, 8 + M_UNSIGNED, M_IMAGE + M_PROC, &blueChannel); // 将 MIL 图像的各个通道复制到单通道缓冲区 MbufCopyColor(mil_img, redChannel, M_RED); MbufCopyColor(mil_img, greenChannel, M_GREEN); MbufCopyColor(mil_img, blueChannel, M_BLUE); // 分别读取每个通道的数据 Mat redMat(height, width, CV_8UC1); Mat greenMat(height, width, CV_8UC1); Mat blueMat(height, width, CV_8UC1); MbufGet(redChannel, redMat.data); MbufGet(greenChannel, greenMat.data); MbufGet(blueChannel, blueMat.data); // 释放通道缓冲区 MbufFree(redChannel); MbufFree(greenChannel); MbufFree(blueChannel); // 合并通道 std::vector bgrChannels = {blueMat, greenMat, redMat}; Mat colorImage; cv::merge(bgrChannels, colorImage); return colorImage; } // 不支持的通道数 std::cerr << "[Error] Unsupported number of channels: " << channels << std::endl; return Mat(); } bool iniColor() { read_params_from_file("C:/Users/Pc/Desktop/color_range_config.txt", params); return 1; } bool iniOnnx() { std::string modelPath = "C:/Users/admin/Desktop/config/dimo_11.14.onnx"; // std::string imagePath = "C:/Users/admin/Desktop/config/463_12.5_M2.bmp"; // cv::Mat image = cv::imread(imagePath); runner.load(modelPath); // cv::Mat mask; // std::vector result = runner.predict(image); // mask = runner.postProcess(result, image); // std::string savepath = "C:/Users/admin/Desktop/config/suspect_mask.png"; // cv::imwrite(savepath, mask); return 1; } bool iniLowMac() { /*--- server socket to faban ---*/ server_to_lowermachine = new QTcpServer(); qDebug()<<"1"; server_to_lowermachine->listen(QHostAddress::Any, 13452); qDebug()<<"2"; bool is_timeout; server_to_lowermachine->waitForNewConnection(5000,&is_timeout); qDebug()<<"3"; if(is_timeout) { return 0; } qDebug()<<"4"; lower_machine = server_to_lowermachine->nextPendingConnection(); qDebug()<<"连接成功"; if (lower_machine == nullptr || !lower_machine->isWritable()) { cout << "Error: Lower machine is not available or writable." << endl; return 0 ; } // // 创建 TCP 服务器对象 // server_to_lowermachine = new QTcpServer(); // // 启动监听 // if (!server_to_lowermachine->listen(QHostAddress::Any, 13452)) { // qDebug() << "Error: Server failed to start."; // return false; // } // qDebug() << "Server is listening on port 13452."; // // 等待新连接 // if (!server_to_lowermachine->waitForNewConnection(5000)) { // qDebug() << "Timeout or no connection."; // return false; // } // // 获取连接 // lower_machine = server_to_lowermachine->nextPendingConnection(); // if (lower_machine) { // qDebug() << "New client connected."; // // 连接数据接收信号 // QObject::connect(lower_machine, &QTcpSocket::readyRead, []() { // QByteArray data = lower_machine->readAll(); // qDebug() << "Received data:" << data; // // 向下位机发送响应 // QByteArray response = "Acknowledged."; // lower_machine->write(response); // }); // // 连接断开信号 // QObject::connect(lower_machine, &QTcpSocket::disconnected, []() { // qDebug() << "Client disconnected."; // lower_machine->deleteLater(); // }); // return true; // } else { // qDebug() << "Error: No client connected."; // return false; // } // 硬编码参数值 int file_delay = 1530; // 延迟时间(毫秒) int file_encoder = 12000; // 编码器值 int file_valve = 200; // 阀门通道 // 计算 Y = 100000000 / X int divide_camera = (file_encoder != 0) ? 100000000 / file_encoder : 0; // 防止除以零的情况 int divide_valve = (file_valve != 0) ? 100000000 / file_valve : 0; // 防止除以零的情况 // 将参数转换为长度为8的字符串,前面补0 QString delay_time = QString("%1").arg(file_delay, 8, 10, QChar('0')); QString divide_parameter = QString("%1").arg(divide_camera, 8, 10, QChar('0')); QString sv_parameter = QString("%1").arg(divide_valve, 8, 10, QChar('0')); // QString delay_time = QString("%1").arg(file_delay, 0, 16); // 去掉补0的部分 // QString divide_parameter = QString("%1").arg(file_encoder, 0, 16); // QString sv_parameter = QString("%1").arg(file_valve, 0, 16); int len_delay = delay_time.size(); int len_divide = divide_parameter.size(); int len_sv = sv_parameter.size(); QByteArray delay_byte = delay_time.toLatin1(); QByteArray divide_byte = divide_parameter.toLatin1(); QByteArray sv_byte = sv_parameter.toLatin1(); // 发送延迟时间 uint8_t* delay_buf = new uint8_t[len_delay + 8]; delay_buf[0] = 0xAA; delay_buf[1] = 0x00; delay_buf[2] = len_delay + 2; delay_buf[3] = 's'; delay_buf[4] = 'd'; memcpy(delay_buf + 5, delay_byte.data(), len_delay); delay_buf[len_delay + 5] = 0xFF; delay_buf[len_delay + 6] = 0xFF; delay_buf[len_delay + 7] = 0xBB; if (lower_machine->isWritable()) { lower_machine->write((const char*)delay_buf, len_delay + 8); } else { cout << "Error: Unable to write to lower machine for delay parameter." << endl; } delete[] delay_buf; // 发送相机参数 uint8_t* divide_buf = new uint8_t[len_divide + 8]; divide_buf[0] = 0xAA; divide_buf[1] = 0x00; divide_buf[2] = len_divide + 2; divide_buf[3] = 's'; divide_buf[4] = 'c'; memcpy(divide_buf + 5, divide_byte.data(), len_divide); divide_buf[len_divide + 5] = 0xFF; divide_buf[len_divide + 6] = 0xFF; divide_buf[len_divide + 7] = 0xBB; if (lower_machine->isWritable()) { lower_machine->write((const char*)divide_buf, len_divide + 8); } else { cout << "Error: Unable to write to lower machine for encoder parameter." << endl; } delete[] divide_buf; // 发送阀门参数 uint8_t* valve_divide_buf = new uint8_t[len_sv + 8]; valve_divide_buf[0] = 0xAA; valve_divide_buf[1] = 0x00; valve_divide_buf[2] = len_sv + 2; valve_divide_buf[3] = 's'; valve_divide_buf[4] = 'v'; memcpy(valve_divide_buf + 5, sv_byte.data(), len_sv); valve_divide_buf[len_sv + 5] = 0xFF; valve_divide_buf[len_sv + 6] = 0xFF; valve_divide_buf[len_sv + 7] = 0xBB; qDebug()<<"相机参数"<isWritable()) { lower_machine->write((const char*)valve_divide_buf, len_sv + 8); } else { cout << "Error: Unable to write to lower machine for valve parameter." << endl; } delete[] valve_divide_buf; return 1; } bool DestoryLowMac() { // 构建停止命令 uint8_t stop_command[9] = {0}; stop_command[0] = 0xAA; // 起始标志 stop_command[1] = 0x00; // 长度高位 stop_command[2] = 0x03; // 长度低位 stop_command[3] = 's'; // 命令类型 stop_command[4] = 'p'; // 停止命令 stop_command[5] = 0xFF; // 校验位1 stop_command[6] = 0xFF; // 校验位2 stop_command[7] = 0xFF; // 校验位3 stop_command[8] = 0xBB; // 结束标志 // 发送停止命令给下位机 if(lower_machine != nullptr && lower_machine->isWritable()) { lower_machine->write(reinterpret_cast(stop_command), 9); lower_machine->flush(); } // 设置运行状态为 false is_running = false; } bool get_valve_data(std::vector> mask) { uint8_t* mask_buf = new uint8_t[4096 + 8]; // 创建缓冲区,大小为3072 + 8 mask_buf[0] = 0xAA; // 起始标志 mask_buf[1] = 0x10; // 高位数据长度 (352 字节 -> 0x0160) mask_buf[2] = 0x02; // 低位数据长度 mask_buf[3] = 'd'; // 命令类型 (发送类型 'd') mask_buf[4] = 'a'; // 数据类型 (阀门相关 'a') // 将二维容器中的二值数据转换为字节并存储到 mask_buf 中 int idx = 5; // 从 mask_buf[5] 开始存储数据 for (int i = 0; i < 512; i++) // 遍历512行 { uint8_t byte = 0; int bit_count = 0; for (int j = 0; j < 64; j++) // 遍历64列 { byte = (byte << 1) | (uint8_t)mask[i][j]; // 将每个二进制位加入到字节中 bit_count++; if (bit_count == 8 || j == 63) // 每8个二进制位打包成一个字节 { mask_buf[idx++] = byte; byte = 0; // 重置byte,开始下一个字节 bit_count = 0; } } } mask_buf[4101] = 0xFF; // 校验低位 mask_buf[4102] = 0xFF; // 校验高位 mask_buf[4103] = 0xBB; // 结束标志 #if(GlobalDebug && DebugLowerMacCOM) for (int i = 0; i <= 4103; i++) { // 将 mask_buf[i] 转换为 int 再输出,避免其被当作字符解释 std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast(mask_buf[i]) << " "; } std::cout << std::endl; #endif // qDebug()<<&mask_buf; // qDebug() << "Sending data to lower machine in binary:"; // for (int i = 0; i < 8200; ++i) // { // QString binaryString = QString::number(mask_buf[i], 2).rightJustified(8, '0'); // qDebug() << QString("Byte %1: %2").arg(i).arg(binaryString); // } // 检查与设备的连接状态 if (lower_machine != nullptr && lower_machine->state() == QAbstractSocket::ConnectedState) { lower_machine->write((const char*)mask_buf, 4104); // 总共 3080 字节 lower_machine->flush(); } else { std::cout << "*** lower machine connect failed! *** " << std::endl; // ui->lab_lowermachine_isconnect->setStyleSheet("QLabel{background-color: rgb(237, 212, 0);}"); // 显示连接失败 // ui->lab_lowermachine_isconnect->repaint(); // 强制刷新UI } delete[] mask_buf; // 释放内存 return 1; } void Start_camera() { MdigProcess(MilDigitizer0, MilGrabBufferList0, 20, M_START, M_DEFAULT,ProcessingFunction0, M_NULL); MdigProcess(MilDigitizer1, MilGrabBufferList1, 20, M_START, M_DEFAULT,ProcessingFunction1, M_NULL); // 发送开始命令 uint8_t start_command[9] = {0}; start_command[0] = 0xAA; start_command[1] = 0x00; start_command[2] = 0x03; start_command[3] = 's'; start_command[4] = 't'; start_command[5] = 0xFF; start_command[6] = 0xFF; start_command[7] = 0xFF; start_command[8] = 0xBB; if (lower_machine != nullptr && lower_machine->isWritable()) { lower_machine->write((const char*)start_command, 9); qDebug()<<"发送相机参数成功"; } else { cout << "Error: Unable to write to lower machine for start command." << endl; } } std::vector > expandArray(const std::vector > &array, int newCols) { int rows = array.size(); // 创建一个新的二维数组,初始化为0,列数为 newCols std::vector> array_total(rows, std::vector(newCols, 0)); // 将原数组的值复制到新数组的前22列 for (int i = 0; i < rows; ++i) { for (int j = 0; j < array[i].size(); ++j) { array_total[i][j] = array[i][j]; } } return array_total; } void VectorToImg(const std::vector > &array, const std::string &image_path) { int height = array.size(); int width = array[0].size(); // 创建一个Mat对象来表示图像,CV_8UC1表示单通道8位无符号整数类型(用于黑白图像) Mat image(height, width, CV_8UC1); // 遍历二维向量,设置图像像素值 for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (array[y][x] == 1) { image.at(y, x) = 255; // 白色像素,对应灰度值255 } else { image.at(y, x) = 0; // 黑色像素,对应灰度值0 } } } // 将图像保存为文件,传入的image_path指定保存路径和文件名 imwrite(image_path, image); } vector> generateMask( const MIL_ID& inputImg, int outputWidth, int outputHeight, int sizeThreshold, int skipLeftCols, int skipRightCols ) { cv::Mat image = mil2mat(inputImg); // Ensure the image is binary cv::threshold(image, image, 128, 255, cv::THRESH_BINARY); int imageWidth = image.cols; int imageHeight = image.rows; // Adjust image width by excluding skipLeftCols and skipRightCols int effectiveWidth = imageWidth - skipLeftCols - skipRightCols; if (effectiveWidth <= 0) { throw std::invalid_argument("Invalid column skip values. Effective width is less than or equal to zero."); } int blockWidth = effectiveWidth / outputWidth; int blockHeight = imageHeight / outputHeight; vector> mask(outputHeight, vector(outputWidth, 0)); for (int i = 0; i < outputHeight; ++i) { for (int j = 0; j < outputWidth; ++j) { int x_start = skipLeftCols + j * blockWidth; int y_start = i * blockHeight; int x_end = (j == outputWidth - 1) ? (imageWidth - skipRightCols) : (skipLeftCols + (j + 1) * blockWidth); int y_end = (i == outputHeight - 1) ? imageHeight : (i + 1) * blockHeight; cv::Mat block = image(cv::Rect(x_start, y_start, x_end - x_start, y_end - y_start)); int whitePixelCount = cv::countNonZero(block); if (whitePixelCount > sizeThreshold) { mask[i][j] = 1; } } } return mask; } pair>, vector>> applyRowRangeDelay( const vector>& mask, const vector>& tail, int rowRange ) { int outputHeight = (int)mask.size(); int outputWidth = (int)mask[0].size(); vector> mask_after_row_range(outputHeight, vector(outputWidth, 0)); vector> newTail(rowRange, vector(outputWidth, 0)); // 先将旧的 tail 映射到 mask_after_row_range 的顶部几行 for (int i = 0; i < (int)tail.size(); ++i) { for (int j = 0; j < outputWidth; ++j) { if (i < outputHeight) { mask_after_row_range[i][j] = max(mask_after_row_range[i][j], tail[i][j]); } } } // 对当前 mask 应用 rowRange 的拖影效果 for (int j = 0; j < outputWidth; ++j) { for (int i = 0; i < outputHeight; ++i) { if (mask[i][j] == 1) { // 从当前行 i 开始,向下扩展 rowRange 行 int end_line = i + rowRange - 1; // 先处理仍在 mask 范围内的部分 int inside_mask_end = min(end_line, outputHeight - 1); for (int line = i; line <= inside_mask_end; ++line) { mask_after_row_range[line][j] = 1; } // 超出 mask 范围的行进入 tail if (end_line >= outputHeight) { // 从 outputHeight 行开始的部分属于 tail for (int line = outputHeight; line <= end_line; ++line) { int tail_line_idx = line - outputHeight; if (tail_line_idx >= 0 && tail_line_idx < (int)newTail.size()) { newTail[tail_line_idx][j] = 1; } } } } } } return {mask_after_row_range, newTail}; } // Updated wrapper function pair>, vector>> generateMaskWithTail( const MIL_ID& inputImg, const vector>& tail, int outputWidth, int outputHeight, int sizeThreshold = 10, int rowRange=1, int skipLeftCols=10, int skipRightCols=10 ) { // Generate the mask from the image vector> mask = generateMask(inputImg, outputWidth, outputHeight, sizeThreshold, skipLeftCols,skipRightCols); // Apply rowRange delay return applyRowRangeDelay(mask, tail, rowRange); } void PadColumns(std::vector>& data, int pad_left, int pad_right, uint8_t fill_value = 0) { // 如果不需要填充,直接返回 if (pad_left <= 0 && pad_right <= 0) { return; } for (auto& row : data) { // 在左侧插入pad_left个fill_value row.insert(row.begin(), pad_left, fill_value); // 在右侧插入pad_right个fill_value row.insert(row.end(), pad_right, fill_value); } } //onnx_Mask