OpenCV技巧篇——多目标视觉定位(以飞镖定位为例)

OpenCV技巧篇【1】——多目标视觉定位(以飞镖定位为例)

1、针对问题

多目标视觉定位是指通过计算机视觉技术对一张图片中的多个目标进行识别和定位的过程。本篇将以对飞镖定位为例,提出一个简单有效的多目标定位技巧,最终实现如下图所示的定位效果。
最终效果

2、解决方法

2.1 颜色筛选

首先要考虑所需定位目标通常具有的最显著的特征——颜色,通过将图片从RGB空间转化到HSV色彩空间筛选出颜色对应的色彩。其中:
H(色调):0-180
S(饱和度):0-255
V(黑暗的程度):0-255
下表是HSV取值范围与对应的色彩(通常需要根据环境光线做出相应的调整,以更好地过滤出目标颜色):

色彩绿
H0~1800~1800~180156~1011~2526~3435~7778~99100~124125~155
S0~2550~430~3043~25543~25543~25543~25543~25543~25543~255
V0~4646~220221~25546~25546~25546~25546~25546~25546~25546~255

opencv代码如下:

# 将图片转到HSV域
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 提取红色
lower_red1 = np.array([0, 43, 46])  # 红色阈值下界
higher_red1 = np.array([10, 255, 255])  # 红色阈值上界
mask_red1 = cv2.inRange(hsv, lower_red1, higher_red1)
lower_red2 = np.array([156, 43, 46])  # 红色阈值下界
higher_red2 = np.array([180, 255, 255])  # 红色阈值上界
mask_red2 = cv2.inRange(hsv, lower_red2, higher_red2)
mask_red = cv2.add(mask_red1, mask_red2)  # 拼接过滤后的mask
cv2.imshow("mask_red", mask_red)
# 提取绿色
lower_green = np.array([35, 43, 46])  # 绿色阈值下界
higher_green = np.array([77, 255, 255])  # 绿色阈值上界
mask_green = cv2.inRange(hsv, lower_green, higher_green)
cv2.imshow("mask_green",mask_green)

绿色飞镖过滤效果如下所示:
在这里插入图片描述

2.2 多目标识别

我们得到了经过颜色过滤后的mask图片,之后需要用ROI将每个单一飞镖裁剪出来,但如何将这多个飞镖的位置分别获取出来就是一个问题,许多人会去使用遍历的方法,通过在各个方向上寻找边缘来定位,但在有多个目标存在的情况下,这种方法往往效果不佳,而这里使用的方法是这样的:

第一步 纵向求和
由于在mask图片中,飞镖区域的值为255,其他区域的值为0,因此可以采用纵向求和的方式(也可以认为是向x轴投影的分布情况),来定位出飞镖的横向坐标范围。
在这里插入图片描述
第二步 横向求和
考虑到有可能出现下图所示的情况,因此在纵向求和获得横向定位坐标范围后,按照此范围内裁剪mask图片,并进行横向求和(也可以认为是向y轴投影的分布情况),来定位出飞镖的纵向坐标范围。最终将得每个到单一飞镖的具体横纵坐标范围。
在这里插入图片描述
同时考虑到背景中存在微量不连续杂色的可能性,可以在获取范围时加入阈值判断,多目标识别具体代码如下:

# 获得X轴分布
x_list_left = []
x_list_right = []
x_distribute = mask_red.sum(axis=0)/255
# plt.plot(mask_red.sum(axis=0)/255)
# plt.plot(mask_red.sum(axis=1)/255)
# plt.show()
# plt.waitforbuttonpress()
for i in range(3,len(x_distribute)-3):if x_distribute[i]==0 and x_distribute[i+1]>0 and x_distribute[i:i+3].sum()>3:x_list_left.append(i)elif x_distribute[i-3:i].sum()>3 and x_distribute[i]>0 and x_distribute[i+1]==0:x_list_right.append(i+1)# 基于X轴,获得Y轴分布,并获得所有可能区域ranges_list = []for j in range(min([len(x_list_left),len(x_list_right)])):y_distribute = mask_red[:,x_list_left[j]:x_list_right[j]].sum(axis=1)/255# 获得Y轴分布y_list_left = []y_list_right = []for i in range(3,len(y_distribute)-3):if y_distribute[i]==0 and y_distribute[i+1]>0 and y_distribute[i:i+5].sum()>3:y_list_left.append(i)elif y_distribute[i-3:i].sum()>3 and y_distribute[i]>0 and y_distribute[i+1]==0:y_list_right.append(i+1)# 获得所有可能区域for i in range(min([len(y_list_left),len(y_list_right)])):if (y_list_right[i]-y_list_left[i]) > 30 and (x_list_right[j]-x_list_left[j]) > 30:ranges_list.append((x_list_left[j],x_list_right[j],y_list_left[i],y_list_right[i]))

第三步 求取坐标
对于如下所示的裁剪出的单一飞镖,只需算得最下层的均值所在位置,即可得到飞镖的像素坐标。
在这里插入图片描述

# 遍历所有飞镖
green_point = []
for i in range(len(ranges_list)):# ROI裁剪max_x = ranges_list[i][1]min_x = ranges_list[i][0]max_y = ranges_list[i][3]min_y = ranges_list[i][2]green_position_x = int(np.where(mask_green[min_x:max_x,min_y:max_y]==255)[0].mean())+min_xgreen_position_y = int(np.where(mask_green[min_x:max_x,min_y:max_y]==255)[1].mean())+min_ycv2.circle(result, green_position,10,(0,255,0),5)green_point.append(green_position)

3、完整代码

对所有红色飞镖进行定位。

import cv2
import numpy as np
import matplotlib.pyplot as pltcap = cv2.VideoCapture(1)while(1):_, frame = cap.read()cv2.imshow("result", frame)hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)# 提取红色lower_red1 = np.array([0, 160, 120])  # 红色阈值下界higher_red1 = np.array([10, 255, 255])  # 红色阈值上界mask_red1 = cv2.inRange(hsv, lower_red1, higher_red1)lower_red2 = np.array([170, 160, 120])  # 红色阈值下界higher_red2 = np.array([180, 255, 255])  # 红色阈值上界mask_red2 = cv2.inRange(hsv, lower_red2, higher_red2)mask_red = cv2.add(mask_red1, mask_red2)  # 拼接过滤后的maskcv2.imshow("mask_red", mask_red)# 获得X轴分布x_distribute = mask_red.sum(axis=0)/255x_list_left = []x_list_right = []for i in range(3,len(x_distribute)-3):if x_distribute[i]==0 and x_distribute[i+1]>0 and x_distribute[i:i+3].sum()>3:x_list_left.append(i)elif x_distribute[i-3:i].sum()>3 and x_distribute[i]>0 and x_distribute[i+1]==0:x_list_right.append(i+1)# 基于X轴,获得Y轴分布,并获得所有可能区域ranges_list = []for j in range(min([len(x_list_left),len(x_list_right)])):y_distribute = mask_red[:,x_list_left[j]:x_list_right[j]].sum(axis=1)/255# 获得Y轴分布y_list_left = []y_list_right = []for i in range(3,len(y_distribute)-3):if y_distribute[i]==0 and y_distribute[i+1]>0 and y_distribute[i:i+3].sum()>3:y_list_left.append(i)elif y_distribute[i-3:i].sum()>3 and y_distribute[i]>0 and y_distribute[i+1]==0:y_list_right.append(i+1)# 获得所有可能区域for i in range(min([len(y_list_left),len(y_list_right)])):if (y_list_right[i]-y_list_left[i]) > 30 and (x_list_right[j]-x_list_left[j]) > 30:ranges_list.append((x_list_left[j],x_list_right[j],y_list_left[i],y_list_right[i]))try:red_point = []for i in range(len(ranges_list)):# ROI裁剪max_x = ranges_list[i][1]min_x = ranges_list[i][0]max_y = ranges_list[i][3]min_y = ranges_list[i][2]flag=0for j in range(max_y-1,min_y-1,-1):if flag==1:breakfor i in range(min_x,max_x):if mask_red[j,i]==255:red_position=(i,j+5)flag=1breakcv2.circle(frame, red_position,10,(0,0,255),5)red_point.append(red_position)print("红色坐标:",red_point)except:cv2.waitKey(5)continuecv2.waitKey(5)
cv2.destroyAllWindows()
cap.release()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1619842.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode 1453. 圆形靶内的最大飞镖数量(几何题)

1. 题目 墙壁上挂着一个圆形的飞镖靶。现在请你蒙着眼睛向靶上投掷飞镖。 投掷到墙上的飞镖用二维平面上的点坐标数组表示。飞镖靶的半径为 r 。 请返回能够落在 任意 半径为 r 的圆形靶内或靶上的最大飞镖数。 示例 1: 输入:points [[-2,0],[2,0…

一个飞镖模型

#飞镖 #一个角 from turtle import* def angle():pu()goto(0,0)pendown()pencolor("black")left(45)fd(50)left(68)fd(91.73)left(157)fd(120)begin_fill()fillcolor("black")right(135)fd(50)right(68)fd(91.73)right(157)fd(120)end_fill()#飞镖复杂化 d…

扔飞镖游戏

日落西山红霞飞~战士打靶把营归呀巴扎嘿。今天我制作一个简单的打靶游戏(扔飞镖) 在制作之前首先要思考这个游戏需要什么对象,很简单,一只飞镖、一个靶。 这里我把飞镖设置成了刚体,什么是刚体?简而言之&…

2022赛规整理——飞镖

2022赛规整理——飞镖 ​ V1.0 2021.10.23 1、比赛场地 (1)打击角度及距离 飞镖口——前哨站:左6.5,直线距离15865mm 飞镖口—— 基地 :右7.3,直线距离25233mm (2)基地示意图 基…

QT之“飞镖盘”自定义控件

QT之“飞镖盘”自定义控件 前言控件预览实现 前言 现在发一个我之前看过有人写了一个抽奖转盘,所以闲来无事写了一个飞镖盘控件,在我看来它其它没有什么实用价值,纯属写来玩玩而已。 控件预览 实现 画背景 void QDartboard::drawBkg(QPai…

在window上配置NASM

NASM是支持x86、x64架构CPU的汇编器(汇编软件);NASM也支持大量的文件格式,包括Linux,*BSD,a.out,ELF,COFF,Mach−O,Microsoft 16−bit OBJ,Win32以及Win64,同…

pc单机版雷电修改器源码

记得以前第一次接触电脑玩的第一个游戏就是雷电,那时候觉得这游戏真好玩,很过瘾。闲来没事干,所以想重温一下游戏,(当时玩的不是这个版本的雷电),那时候是和小伙伴一起玩的,可惜现在…

《愤怒的小鸟》登陆PC 绿色免安装版首发

这群去年风靡手机的小鸟就不用过多的介绍了,一个月前其开发商游戏开发商Rovio表示将会推出PC版。今天为大家带来的就是绿色免安装版的愤怒的小鸟。 游戏的玩法很简单,将弹弓上的小鸟弹出去,砸到绿色的肥猪,将肥猪全部砸到就能过关…

Pygame小游戏之俄罗斯方块凭什么火了30年?(史上最畅销单机游戏)

前言 一款俄罗斯方块火了30年,成为有史以来最畅销的单机游戏。 它为什么有那么的魔力经久不衰? 小编总结了一些原因:上手极其简单,技巧却很多,满足在混乱中创造秩序的渴望…… 工程师阿列克谢说,人们并没有意识到&…

硬盘图标修改器 V1.0 绿色版

软件名称:硬盘图标修改器 V1.0 绿色版软件语言: 简体中文授权方式: 免费软件应用平台: Win7 / Vista / Win2003 / WinXP / Win2008 软件大小: 12.3MB图片预览: 软件简介:是否厌倦了千篇一律的Windows硬盘图…

Java多线程与并发编程

课程地址: https://www.itlaoqi.com/chapter.html?sid98&cid1425 源码文档: 链接:https://pan.baidu.com/s/1WMvM3j6qhyjIeAT87kIcxg 提取码:5g56 Java多线程与并发编程 1-并发背后的故事什么是并发 2-你必须知道线程的概念程…

“黑客”入门学习之“单机游戏外挂原理与实现”

“黑客”入门学习之“单机游戏外挂原理与实现”(文末全套黑客资料教程) 昨天给小伙伴们分享了一篇"游戏外挂原理与实现"的文章,小伙伴们很热情,反响很好,好多朋友私信我,或者直接回复我"写…

PMP P-03 Scope Management

范围管理:要做多少事情,内容

数据生成 | MATLAB实现GAN生成对抗网络结合SVM支持向量机的数据生成

数据生成 | MATLAB实现GAN生成对抗网络结合SVM支持向量机的数据生成 目录 数据生成 | MATLAB实现GAN生成对抗网络结合SVM支持向量机的数据生成生成效果基本描述程序设计参考资料 生成效果 基本描述 数据生成 | MATLAB实现GAN生成对抗网络结合SVM支持向量机的数据生成。 生成对抗…

代码随想录算法训练营第四十七天|LeetCode 382,115

目录 LeetCode 392.判断子序列 动态规划五步曲: 1.确定dp[i][j]的含义 2.找出递推公式 3.初始化dp数组 4.确定遍历顺序 5.打印dp数组 LeetCode 115.不同的子序列 动态规划五步曲: 1.确定dp[i][j]的含义 2.找出递推公式 3.初始化dp数组 4.确定遍历顺序 …

压缩包密码的破解

给压缩包添加密码 解密 将压缩包的加密信息放入新建的文本文档 zip2john 123.zip > mima.txt 使用john解密 john mima.txt john的密码字典路径 cd /etc/share/john ls 查看有多少行密码

压缩包解压密码怎么破

从网上下载的资源大多数都是以压缩包形式被下载下来,我们需要通过解压压缩包拿到我们想要的文件,但是有时候可能会遇到解压压缩包的时候需要密码的情况,那压缩包解压秘密该怎么破解呢?如果文件资源对你来说很重要的话,…

Linux系统:CentOS 7 CA证书服务器部署

目录 一、理论 1.CA认证中心 2.CA证书服务器部署 二、实验 1. CA证书服务器部署 一、理论 1.CA认证中心 (1)概念 CA :CertificateAuthority的缩写,通常翻译成认证权威或者认证中心,主要用途是为用户发放数字证…

D - President - 背包dp

分析: 需要让所有x大于y的对应的z的总数大于z总共的数量的一半,找最小需要转化的数量,那么可以转化为01背包问题,z作为体积,每组的x和y都可以计算出一个值表示需不需要转化,作为背包价值,如果x大…

利用阿里云服务器公网IP+FRP搭建内网穿透

1 必要条件: 一台公网IP服务器,这里采用阿里云ECS服务器。 此处将IP定义为:serverA-IP 2 服务器下载代码: # mkdir /data # cd /data # git clone https://github.com/fatedier/frp.git # cd frp3 编译代码 编译需要时间 # make go fmt .…