在图像中查找指定颜色
| 730 | |
| 731 | // 在图像中查找指定颜色 |
| 732 | bool Utils::findColorEx(const cv::Mat& image, int x1, int y1, int x2, int y2, const QString& hexColor, double tolerance, int& outX, int& outY) { |
| 733 | // 检查 tolerance 是否在有效范围 [0, 1] |
| 734 | if (tolerance < 0.0 || tolerance > 1.0) { |
| 735 | qWarning() << "Tolerance should be between 0 and 1."; |
| 736 | outX = -1; |
| 737 | outY = -1; |
| 738 | return false; |
| 739 | } |
| 740 | |
| 741 | |
| 742 | // 转换颜色 |
| 743 | cv::Vec3b targetColor; |
| 744 | bool isConvertColor = Utils::hexToBGR(hexColor, targetColor); |
| 745 | if (!isConvertColor) { |
| 746 | qWarning() << "Failed to convert hex color to BGR."; |
| 747 | outX = -1; |
| 748 | outY = -1; |
| 749 | return false; |
| 750 | } |
| 751 | |
| 752 | // 限制搜索区域,确保区域在图像范围内 |
| 753 | x1 = std::max(0, x1); |
| 754 | y1 = std::max(0, y1); |
| 755 | x2 = std::min(image.cols, x2); |
| 756 | y2 = std::min(image.rows, y2); |
| 757 | |
| 758 | if (x2 <= x1 || y2 <= y1) { |
| 759 | qWarning() << "Invalid search region."; |
| 760 | outX = -1; |
| 761 | outY = -1; |
| 762 | return false; |
| 763 | } |
| 764 | |
| 765 | cv::Rect searchRegion(x1, y1, x2 - x1, y2 - y1); |
| 766 | cv::Mat region = image(searchRegion); |
| 767 | |
| 768 | // 计算最大可能的颜色距离 |
| 769 | const double max_distance = std::sqrt(3.0 * 255.0 * 255.0); // ~441.67 |
| 770 | |
| 771 | // 计算允许的最大距离,根据 tolerance 反转逻辑 |
| 772 | double allowed_distance = (1.0 - tolerance) * max_distance; |
| 773 | |
| 774 | // 遍历搜索区域内的所有像素 |
| 775 | for (int y = 0; y < region.rows; ++y) { |
| 776 | for (int x = 0; x < region.cols; ++x) { |
| 777 | cv::Vec3b pixelColor = region.at<cv::Vec3b>(y, x); |
| 778 | |
| 779 | // 计算颜色差异(欧几里得距离) |
| 780 | double distance = std::sqrt( |
| 781 | std::pow(static_cast<double>(pixelColor[0]) - targetColor[0], 2) + // B |
| 782 | std::pow(static_cast<double>(pixelColor[1]) - targetColor[1], 2) + // G |
| 783 | std::pow(static_cast<double>(pixelColor[2]) - targetColor[2], 2) // R |
| 784 | ); |
| 785 | |
| 786 | // 判断是否满足容忍误差 |
| 787 | if (distance <= allowed_distance) { |
| 788 | outX = x1 + x; // 转换为原图的坐标 |
| 789 | outY = y1 + y; |