java-opencv简单识别箭头

前言

对形状识别了解的不是太多,本篇算是个简单入门。因为最近比较忙闲暇时间不多了解的不算深入写的有不对的地方还请评论区留言。

声明下 :还有这里的识别没有用深度学习最近在学demo,也没用模板匹配类的(很久前写了一个象棋棋谱识别的例子用的模板一个一个匹配的:象棋棋谱之棋子识别(三))。

这里学习参考了网上的一些思路用java写了个demo,形状的话常见的有三角形、正方形、长方形、平行四边形、梯形因为定义公式也比较简单所以识别也相对容易;多边形类的就需要自己发现特点然后去处理了。

思路

  1. 首先轮廓提取。
  2. 因为轮廓是由一个一个点连线得到的所以需要获取轮廓的点的坐标和个数。
  3. 得到轮廓凸包的坐标点的索引。(凸包就是最外层的连线下图红色。所有的点是通过轮廓得到的。中间的排除掉了是凸包得到的就是最外层的点)
  1. 能拿到点我们也就能做很多东西了。常见的形状识别例如正方形:是四个点、四条边长相等、每个角度是90°、我们也可以不通过角度通过计算用面积是否跟正方形的面积相等进行判断。对于边长和角度我们可以对坐标点排序(也就是顺时针、逆时针)然后计算得到,角度应该有API的。

本篇的箭头识别demo

效果

这里再说下凸包看下下图就明白了绿线

处理的方式

先说下外面的7个点,这是个逆时针标识的

  1. 首先获取轮廓,参数意思可以在网上搜这里不在多写了。或者参考我之前写的一篇(java调用opencv轮廓检测
bash 复制代码
Imgproc.findContours(clone, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
  1. 首先这个箭头是由七个坐标点组成的,进行坐标点个数判断。
arduino 复制代码
//多边形包围轮廓
Imgproc.approxPolyDP(curve, approxCurve, 0.025 * Imgproc.arcLength(curve, true), true);
//这个参数就是返回的坐标点
approxCurve.toArray().length
  1. 然后凸包得到的坐标点会比正常的点数少2个。
vbscript 复制代码
//true=顺时针方向 false=逆时针方向 这里我观察了下开始是从上面中间的位置开始的
//hull.toArray().length 返回的是上面approxPolyDP得到的坐标位置
Imgproc.convexHull(CommonCVUtils.poit2fTOPoint(approxCurve), hull, true);
int arrIndex[] = hull.toArray();
  1. 箭头的顶点判断做了些特殊处理,是根据少的点数(中间的两个点)判断出来的根据先后顺序。首先得到少的是那些顶点。方法可能有些笨(可以在评论区指出)
ini 复制代码
//第一个参数是 2多边形包围轮廓的顶点
//第二个参数是 4凸包得到的顶点索引(第一个参数的索引)
public static Point findTip(MatOfPoint contour, MatOfInt indexes) {
    int arrIndex[] = indexes.toArray();
    Point arrContour[] = contour.toArray();
    //得到少的顶点位置
    int indices[] = new int[2];
    int k=0;
    for(int j=0;j<arrContour.length;j++){
        boolean flag = false;
        for(int i=0;i<arrIndex.length;i++){
            if(arrIndex[i]==j){
              flag=true;
              break;
            }
        }
        if(!flag){
            indices[k++]=j;
        }
    }

    //得到最小的顶点和最大的顶点坐标
    int index0=Math.min(indices[0],indices[1]);
    int index1=Math.max(indices[0],indices[1]);

    //箭头朝左 凸包内的点第二个就是
    if(index1==arrContour.length-1 && index0 - 2>-1){
        return arrContour[index0 - 2];
    }

    //箭头朝下
    if(index1-index0==4) {
        return arrContour[index0+2];
    }else{
    //这里的判断是上和右
        if (index1 + 2 > arrContour.length - 1) {
            return arrContour[arrContour.length - index1 - 2];
        } else {
            return arrContour[index1 + 2];
        }
    }
}

结束。

相关推荐
运行时记录15 分钟前
prompt-optimizer skill
算法
万法若空25 分钟前
【数据结构-哈希表】哈希表原理
数据结构·算法·散列表
极客先躯39 分钟前
高级java每日一道面试题-2026年03月30日-实战篇[Docker]-如何监控容器的网络流量?
java·运维·docker·容器·prometheus·高级面试
退休倒计时40 分钟前
【每日一题】LeetCode 437. 路径总和 III TypeScript
算法·leetcode·typescript
学逆向的1 小时前
汇编——内存
开发语言·汇编·算法·网络安全
tachibana21 小时前
hot100 翻转二叉树(226)
java·数据结构·算法·leetcode
brave_zhao1 小时前
nginx的进程架构
java·学习·nginx
兰令水1 小时前
leecodecode【面试150】【2026.7.9打卡-java版本】
java·数据结构·leetcode·面试·职场和发展
禾高网络1 小时前
互联网医院|AI 互联网医院成品开发系统
java·大数据·人工智能·小程序
shepherd1111 小时前
一次把 Spring MVC 文件上传参数“查没了”的排查:multipart、Filter 与 request body 的连环坑
java·spring boot·后端