opencv实现点到region最小距离,distance_pr

distance_pr的算子很快

使用opencv模仿实现一下

halcon 的 region使用rle编码,还有可能使用凸包优化,simd,二分查找,多线程计算,这里只实现基础的功能

复制代码
#include <opencv2/opencv.hpp>
#include <vector>
#include <limits>
#include <algorithm>

// 结构体表示RLE编码的区域点
struct RLEPoint {
    int y;
    int x_start;
    int x_end;
};

// 从二值图像生成RLE编码的区域表示
std::vector<RLEPoint> binaryImageToRLE(const cv::Mat& binImage) {
    std::vector<RLEPoint> rlePoints;
    CV_Assert(binImage.type() == CV_8UC1);
    
    for (int y = 0; y < binImage.rows; ++y) {
        const uchar* row = binImage.ptr<uchar>(y);
        bool inRun = false;
        int runStart = 0;
        
        for (int x = 0; x < binImage.cols; ++x) {
            if (row[x] > 0) { // 前景像素
                if (!inRun) {
                    inRun = true;
                    runStart = x;
                }
            } else {
                if (inRun) {
                    inRun = false;
                    rlePoints.push_back({y, runStart, x-1});
                }
            }
        }
        
        if (inRun) {
            rlePoints.push_back({y, runStart, binImage.cols-1});
        }
    }
    
    return rlePoints;
}

// 计算凸包点集
std::vector<cv::Point> computeConvexHull(const std::vector<RLEPoint>& rlePoints) {
    std::vector<cv::Point> allPoints;
    
    // 将RLE点转换为离散点
    for (const auto& rle : rlePoints) {
        for (int x = rle.x_start; x <= rle.x_end; ++x) {
            allPoints.emplace_back(x, rle.y);
        }
    }
    
    // 计算凸包
    std::vector<cv::Point> hull;
    cv::convexHull(allPoints, hull);
    return hull;
}

// 射线法判断点是否在凸包内
bool isPointInConvexHull(const cv::Point& p, const std::vector<cv::Point>& hull) {
    if (hull.size() < 3) return false;
    
    // 检查点是否在所有边的同一侧
    int prevSide = 0;
    for (size_t i = 0; i < hull.size(); ++i) {
        const cv::Point& p1 = hull[i];
        const cv::Point& p2 = hull[(i+1)%hull.size()];
        
        // 计算叉积
        int cross = (p2.x - p1.x) * (p.y - p1.y) - (p2.y - p1.y) * (p.x - p1.x);
        
        if (cross == 0) continue; // 在边上
        
        int currentSide = cross > 0 ? 1 : -1;
        if (prevSide == 0) {
            prevSide = currentSide;
        } else if (currentSide != prevSide) {
            return false;
        }
    }
    
    return true;
}

// 优化的distance_pr实现
double optimized_distance_pr(const cv::Mat& region, const cv::Point& queryPoint) {
    // 1. 转换为RLE编码表示
    auto rlePoints = binaryImageToRLE(region);
    if (rlePoints.empty()) return std::numeric_limits<double>::max();
    
    // 2. 计算凸包
    auto convexHull = computeConvexHull(rlePoints);
    
    // 3. 检查查询点是否在凸包内
    bool inside = isPointInConvexHull(queryPoint, convexHull);
    
    // 4. 计算最小距离
    double minDist = std::numeric_limits<double>::max();
    
    if (inside) {
        // 如果在凸包内,距离可能为0,需要检查精确包含关系
        for (const auto& rle : rlePoints) {
            if (rle.y == queryPoint.y) {
                if (queryPoint.x >= rle.x_start && queryPoint.x <= rle.x_end) {
                    return 0.0; // 点在区域内
                }
            }
        }
    }
    
    // 5. 使用凸包顶点快速估算搜索范围
    double searchRadius = std::numeric_limits<double>::max();
    for (const auto& p : convexHull) {
        double dx = p.x - queryPoint.x;
        double dy = p.y - queryPoint.y;
        double dist = std::sqrt(dx*dx + dy*dy);
        if (dist < searchRadius) {
            searchRadius = dist;
        }
    }
    
    // 6. 在RLE点集中搜索最小距离
    for (const auto& rle : rlePoints) {
        // 快速检查是否可能在搜索范围内
        if (std::abs(rle.y - queryPoint.y) > searchRadius) continue;
        
        // 计算到该行的最小距离
        int closestX = std::max(rle.x_start, std::min(rle.x_end, queryPoint.x));
        double dx = closestX - queryPoint.x;
        double dy = rle.y - queryPoint.y;
        double distance = std::sqrt(dx*dx + dy*dy);
        
        if (distance < minDist) {
            minDist = distance;
            // 更新搜索半径
            if (distance < searchRadius) {
                searchRadius = distance;
            }
        }
    }
    
    return minDist;
}
相关推荐
hans汉斯10 分钟前
【人工智能与机器人研究】基于力传感器坐标系预标定的重力补偿算法
人工智能·算法·机器人·信号处理·深度神经网络
cver12318 分钟前
CSGO 训练数据集介绍-2,427 张图片 AI 游戏助手 游戏数据分析
人工智能·深度学习·yolo·目标检测·游戏·计算机视觉
FreeBuf_22 分钟前
新型BERT勒索软件肆虐:多线程攻击同时针对Windows、Linux及ESXi系统
人工智能·深度学习·bert
强哥之神1 小时前
Meta AI 推出 Multi - SpatialMLLM:借助多模态大语言模型实现多帧空间理解
人工智能·深度学习·计算机视觉·语言模型·自然语言处理·llama
成都极云科技1 小时前
成都算力租赁新趋势:H20 八卡服务器如何重塑 AI 产业格局?
大数据·服务器·人工智能·云计算·gpu算力
喜欢吃豆1 小时前
从零构建MCP服务器:FastMCP实战指南
运维·服务器·人工智能·python·大模型·mcp
ai_xiaogui1 小时前
AIStarter用户与创作者模式详解:一键管理Stable Diffusion项目!
人工智能·stable diffusion·一键发布ai项目·熊哥aistarter教程·开发者必备aistarter
止步前行2 小时前
Cursor配置DeepSeek调用MCP服务实现任务自动化
人工智能·cursor·deepseek·mcp
阿星AI工作室2 小时前
AI产品经理必看的大模型微调劝退指南丨实战笔记
人工智能·产品经理·ai编程
Damon小智2 小时前
蚂蚁百宝箱实战:艺考生文化课助手的设计与搭建
人工智能·mcp