/* * 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" #include #include 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; } static int _remove_dir_recursive_(const std::string &dir_path) { DIR *dir = opendir(dir_path.c_str()); if (!dir) { // 如果目录不存在,视为成功(因为目标是不存在) if (errno == ENOENT) return 0; printf("opendir[%s] error: %s\n", dir_path.c_str(), strerror(errno)); return -1; } struct dirent *entry; while ((entry = readdir(dir)) != nullptr) { std::string name = entry->d_name; // 跳过 . 和 .. if (name == "." || name == "..") { continue; } std::string full_path = dir_path + "/" + name; struct stat st; // 获取文件状态,使用 lstat 以处理符号链接 if (lstat(full_path.c_str(), &st) == -1) { printf("lstat[%s] error: %s\n", full_path.c_str(), strerror(errno)); continue; } // 如果是目录,递归删除 if (S_ISDIR(st.st_mode)) { if (_remove_dir_recursive_(full_path) != 0) { closedir(dir); return -1; } // 删除空子目录 if (rmdir(full_path.c_str()) != 0) { printf("rmdir[%s] error: %s\n", full_path.c_str(), strerror(errno)); closedir(dir); return -1; } } else { // 如果是文件(或符号链接等),直接删除 if (remove(full_path.c_str()) != 0) { printf("remove[%s] error: %s\n", full_path.c_str(), strerror(errno)); closedir(dir); return -1; } } } closedir(dir); 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); int nonZeroCount = cv::countNonZero(mask); // printf("===========1== hj %f nonZeroCount %d\n", meanValue123[0], nonZeroCount); if (nonZeroCount > 100) { cv::Mat element; if (nonZeroCount > 1500) { element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(11, 11)); } else if (nonZeroCount > 1000) { element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(7, 7)); } else if (nonZeroCount > 500) { element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5)); } else { element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); } // 进行腐蚀操作 cv::Mat erodedMask; cv::erode(mask, erodedMask, element); int nonZeroCount111 = cv::countNonZero(erodedMask); if (nonZeroCount111 > 100) { meanValue123 = cv::mean(absDiff, erodedMask); // printf("========2===== hj %f nonZeroCount %d\n", meanValue123[0], nonZeroCount111); } } // if (meanValue123[0] > 100) // { // // 打印 32F 像素值 // for (int i = 0; i < absDiff.rows; ++i) // { // for (int j = 0; j < absDiff.cols; ++j) // { // std::cout << "Pixel value at (" << i << ", " << j << "): " // << absDiff.at(i, j) << std::endl; // } // } // } 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]; } float CheckUtil::CalRoi2RoiPre(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(); double iou = 0; if (union_area != 0) { iou = intersection_area / union_area; } // 计算IoU值 return iou; } 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; } int CheckUtil::DeleteDir(const std::string &dir) { if (dir.empty()) { return -1; } // 检查路径是否存在 struct stat st; if (stat(dir.c_str(), &st) != 0) { // 目录不存在,视为成功 return 0; } // 如果不是目录,可能是文件,尝试直接删除 if (!S_ISDIR(st.st_mode)) { if (remove(dir.c_str()) == 0) { return 0; } else { printf("remove file[%s] error: %s\n", dir.c_str(), strerror(errno)); return -1; } } // 是目录,先递归清空内容 if (_remove_dir_recursive_(dir) != 0) { return -1; } // 最后删除空目录本身 if (rmdir(dir.c_str()) != 0) { printf("rmdir[%s] error: %s\n", dir.c_str(), strerror(errno)); return -1; } // printf("remove dir[%s] success.\n", dir.c_str()); return 0; } 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::Point2f p1, cv::Point2f 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)); }