当前位置: 首页 > news >正文

[二值图像处理] 骨架线提取、骨架端点、交叉点提取

提取骨架线,骨架端点和交叉点的效果图

认识骨架线(Skeleton)

骨架线是通过细化算法(二值图像骨架提取)提取得到的4邻域或8邻域线条,一般效果如下图所示。在骨架图像拓扑分析时,骨架的端点和交叉点尤为重要。下面我们介绍形态学的击中击不中(hit-and-miss)算法如何在骨架图像上提取这些关键点。

骨架端点(LineEnds)提取

端点提取的模板如下图所示,

从模板的结构上可以发现,它只匹配至少有两个像素的线条,匹配的像素被背景像素 "盖住 "或 "包围"。

opencv实现端点提取的代码如下:

int SkeletonGetEndPt(const cv::Mat& skeletonImg, vector<cv::Point>& endPoints) {cv::Mat zerOneImg, padImg;endPoints.clear();cv::copyMakeBorder(skeletonImg, padImg, 1, 1, 1, 1, CV_8UC1, cv::Scalar(0));cv::threshold(padImg, zerOneImg, 0, 1, cv::THRESH_BINARY);#pragma region kernerl// http ://www.imagemagick.org/Usage/morphology/#linejunctions// 1表示图像中的(白色)前景结构,-1表示(黑色)背景结构,0表示忽略位置。cv::Mat kernel1 = (cv::Mat_<int>(3, 3) << -1, -1, 0,-1,  1, 1,-1, -1, 0);cv::Mat kernel2 = (cv::Mat_<int>(3, 3) << -1, -1, -1,-1,  1, -1,0,  1,  0);cv::Mat kernel3 = (cv::Mat_<int>(3, 3) << 0, -1, -1,1,  1, -1,0, -1, -1);cv::Mat kernel4 = (cv::Mat_<int>(3, 3) << 0,  1,  0,-1,  1, -1,-1, -1, -1);cv::Mat kernel5 = (cv::Mat_<int>(3, 3) << -1, -1, -1,-1,  1, -1,-1, -1,  1);cv::Mat kernel6 = (cv::Mat_<int>(3, 3) << -1, -1, -1,-1,  1, -1,1, -1, -1);cv::Mat kernel7 = (cv::Mat_<int>(3, 3) << 1, -1, -1,-1,  1, -1,-1, -1, -1);cv::Mat kernel8 = (cv::Mat_<int>(3, 3) << -1, -1,  1,-1,  1, -1,-1, -1, -1);#pragma endregioncv::Mat endPointsImg, hitmisImg;endPointsImg.create(padImg.size(), CV_8UC1);endPointsImg.setTo(0);vector<cv::Mat> kerners{ kernel1,kernel2,kernel3,kernel4,kernel5,kernel6,kernel7,kernel8 };for (const cv::Mat& ker : kerners) {cv::morphologyEx(zerOneImg, hitmisImg, cv::MorphTypes::MORPH_HITMISS, ker);cv::bitwise_or(hitmisImg, endPointsImg, endPointsImg);}endPointsImg = endPointsImg * 255;for (int r = 0; r < endPointsImg.rows; r++) {for (int c = 0; c < endPointsImg.cols; c++) {if (endPointsImg.at<uchar>(r, c) > 0) {endPoints.emplace_back(c - 1, r - 1);}}}return 0;
}

图中绿色点为骨架线端点

骨架交叉点(LineJunctions)提取

LineJunctions模板将找到3条或更多的线形成的交界处的点,模板核如下图所示。

opencv实现代码如下:

int SkeletonGetJunctionPt(const cv::Mat& biImg,vector<cv::Point>& ptPairVec) {cv::Mat zerOneImg, padImg;ptPairVec.clear();cv::copyMakeBorder(biImg, padImg, 1, 1, 1, 1, CV_8UC1, cv::Scalar(0));cv::threshold(padImg, zerOneImg, 0, 1, cv::THRESH_BINARY);
#pragma region kernerlcv::Mat kernel1 = (cv::Mat_<uchar>(3, 3) << 1, 0, 1,0, 1, 0,0, 1, 0);cv::Mat kernel2 = (cv::Mat_<uchar>(3, 3) << 0, 1, 0,0, 1, 1,1, 0, 0);  cv::Mat kernel3 = (cv::Mat_<uchar>(3, 3) << 0, 0, 1,1, 1, 0,0, 0, 1);cv::Mat kernel4 = (cv::Mat_<uchar>(3, 3) << 1, 0, 0,0, 1, 1,0, 1, 0);cv::Mat kernel5 = (cv::Mat_<uchar>(3, 3) << 0, 1, 0,0, 1, 0,1, 0, 1);cv::Mat kernel6 = (cv::Mat_<uchar>(3, 3) << 0, 0, 1,1, 1, 0,0, 1, 0);cv::Mat kernel7 = (cv::Mat_<uchar>(3, 3) << 1, 0, 0,0, 1, 1,1, 0, 0);cv::Mat kernel8 = (cv::Mat_<uchar>(3, 3) << 0, 1, 0,1, 1, 0,0, 0, 1);cv::Mat kernel9 = (cv::Mat_<uchar>(3, 3) << 1, 0, 0,0, 1, 0,1, 0, 1);cv::Mat kernel10 = (cv::Mat_<uchar>(3, 3) << 1, 0, 1,0, 1, 0,1, 0, 0);  cv::Mat kernel11 = (cv::Mat_<uchar>(3, 3) <<1, 0, 1,0, 1, 0,0, 0, 1);cv::Mat kernel12 = (cv::Mat_<uchar>(3, 3) <<0, 0, 1,0, 1, 0,1, 0, 1);
#pragma endregioncv::Mat intersecImg,hitmisImg;intersecImg.create(padImg.size(), CV_8UC1);intersecImg.setTo(0);vector<cv::Mat> kerners{ kernel1,kernel2,kernel3,kernel4,kernel5,kernel6,kernel7,kernel8,kernel9,kernel10,kernel11,kernel12 };for (cv::Mat ker:kerners)  {cv::morphologyEx(zerOneImg, hitmisImg, cv::MorphTypes::MORPH_HITMISS, ker);cv::bitwise_or(hitmisImg, intersecImg, intersecImg);}intersecImg = intersecImg * 255;for (int r = 0; r < intersecImg.rows; r++) {for (int c = 0; c < intersecImg.cols; c++) {if (intersecImg.at<uchar>(r, c) > 0) {ptPairVec.push_back(cv::Point(c - 1, r - 1));}}}return 0;
}

图中红色点为骨架线交叉点

提取交叉点和端点的效果。

有个端点和交叉点后,我们可以进一步分析骨架图像的拓扑结构等信息,进而对骨架进行分叉去除、长度计算、主干提取等操作。


http://www.mrgr.cn/news/96142.html

相关文章:

  • Ollama未授权访问
  • 力扣:回溯算法
  • AS400==WINDOWS开发COBOL/安装DB2/连接DB2
  • 学有所记——初探向量数据库Weaviate
  • 深度学习入门1 基于Python的理论与实现
  • kubeadm部署k8s-1.32版本集群(1个master,1个worker)
  • 电机控制常见面试问题(二十)
  • 每日一题-力扣-2829. k-avoiding 数组的最小总和 0326
  • gz sim机器人SDF模型 [持续更新]
  • [unity 点击事件] 区域响应点击事件,排除子节点区域,Raycast Target 应用
  • Android实践开发制作小猴子摘桃小游戏
  • 系统架构设计知识体系总结
  • 在 Linux(Ubuntu / CentOS 7)上快速搭建我的世界 MineCraft 服务器,并实现远程联机,详细教程
  • 给Web开发者的HarmonyOS指南01-文本样式
  • 数学-算法
  • Unity-RectTransform设置UI width
  • 生成模型速通(Diffusion,VAE,GAN)
  • 【更新中】【React】基础版React + Redux实现教程,自定义redux库和react-redux库
  • Mac 常用命令
  • @Resource 与 @Autowired:Spring 中的依赖注入注解大比拼