OpenCV(9)-图像轮廓

news2024/11/19 10:22:50

图像轮廓

图像轮廓概述

  • 图像轮廓是具有相同颜色强度连续点的曲线

  • 作用:

    • 可以用于图形分析
    • 物体的识别与检测
  • 注意:

    • 为了检测的准确性,需要先对图像进行二值化或Canny操作
    • 画轮廓时会修改输入的图像
  • 轮廓查找API:

  • findContours(img,mode,ApproximationMode,…)

    • mode:模式,对查找到的轮廓如何处置
      • RETR_EXTERNAL = 0, 表示只检测外轮廓
      • RETR_LIST = 1,检测的轮廓不建立等级关系
      • RETR_CCOMP = 2,每层最多两级
      • RETR_TREE = 3,按树形存储轮廓
    • ApproximationMode:近似模式
      • CHAIN_APPROX_NODE,保存所有轮廓上的点
      • CHAIN_APPROX_SIMPLE,只保存角点
  • 有两个返回值:contours(所有轮廓)和hierarchy(层级关系)

查找轮廓

#转变成单通道
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#二值化
ret,binary = cv2.threshold(gray,150,255,cv2.THRESH_BINARY)
#轮廓查找
contours,hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

绘制轮廓

  • drawContours(img,contours,contourIdx,color,thichness…)
    • contourIdx轮廓顺序号,-1表示绘制所有轮廓
    • color轮廓颜色
    • thichness线宽,-1是全部填充
#绘制轮廓
cv2.drawContours(img,contours,-1,(0,0,255),1)

轮廓的面积和周长

  • 轮廓的面积contourArea(contour)
  • 轮廓的周长arcLength(curve,closed)
    • curve轮廓曲线
    • closed是否是闭合的轮廓
#计算面积
area = cv2.contourArea(contours[0])
print("area = %d"%(area))
#计算周长
len = cv2.arcLength(contours[0],true)

多边形逼近与凸包

  • 多边形逼近,可凸可凹,更接近真实物体
  • 多边形逼近作用:减少了存储的数据量,同时将特征点描述出来
    • 特征点可多可少,精度调高,逼近更真实;反之则数据量更少
  • approxPolyDP(curve,epsilon,closed)
    • curve 曲线、轮廓
    • epsilon 精度
    • closed 是否是闭合曲线
e = 20 #设置精度
approx = cv2.approxPolyDP(contours[0],e,True)
#画线函数
def drawShape(src,points):
    while i < len(points):
        if(i == len(points) - 1)
        	x,y = points[i][0]
        	x1,y1 = points[0][0]
        	cv2.line(src,(x,y),(x1,y1),(0,0,255),3)
        else:
            x,y = points[i][0]
        	x1,y1 = points[i+1][0]
        	cv2.line(src,(x,y),(x1,y1),(0,0,255),3)
        i = i + 1
#绘制
drawShape(img,approx)
  • 凸包:只能凸出,不会下凹,只画出大致轮廓
  • convexHull(points,clockwise,…)
    • points 轮廓
    • clockwise 顺时针绘制
hull = cv2.convexHull(contours[0])
drawShape(img,hull)

外接矩阵

  • 最小外接矩阵 红框 知道物体有没有旋转,以及旋转角度
  • minAreaRect(points)
    • points 轮廓
    • 返回值:RotatedRect
      • x,y 起始点
      • width,height
      • angle 旋转角度
  • 最大外接矩阵 绿框
  • boundingRect(array)
    • array 轮廓
    • 返回值:Rect
      • x,y 起始点
      • width,height
        在这里插入图片描述
r = minAreaRect(contours[1])
box = cv2.boxPoints(r) #拿到起始点和宽高
box = np.int0(box) #将浮点型box转换为int型
cv2.drawContours(img,[box],0,(0,0,255),2)
x,y,w,h = cv2.boundingRect(contours[1])
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)

[实战]车辆统计

项目总览

涉及到的内容

  • 窗口的展示
  • 图像/视频的加载
  • 基本图像的绘制
  • 车辆识别
    • 基本图像的运算与处理
    • 形态学
    • 轮廓查找

涉及到的知识点

  • 加载视频
  • 通过形态学识别车辆
  • 对车辆进行统计
  • 显示车辆的统计信息

加载视频

import cv2
import numpy as np

#加载视频
cap = cv2.VideoCapture('video.mp4')

#视频由很多帧组成 循环读取
while True:
    ret, frame = cap.read() #ret读取视频帧是否成功,frame读取视频帧
    if(ret == True):
        cv2.imshow('video',frame)
        
    key = cv2.waitKey(1)
    if(key == 27): #27为ESC键
        break
#释放资源
cap.release()
cv2.destroyAllWindows()

去除背景

  • createBackgroundSubtractorMOG(…)
    • history = 200
bgsubmog = cv2.createBackgroundSubtractorMOG()

形态学处理

#腐蚀,去除图中小斑块
erode = cv2.eroed(mask,kernel)
#膨胀,还原放大
dilate = cv2.dilate(erode,kernel,iterations = 3)
#闭操作,去除物体内部的小块
close = cv2.morphologyEx(dilate,cv2.MORPH_CLOSE,kernel)
close = cv2.morphologyEx(close,cv2.MORPH_CLOSE,kernel)
#绘制轮廓
cnts, h = cv2.findContours(close,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
for(i,c) in enumerate(cnts):
    (x,y,w,h) = cv2.boundingRect(c)
    cv2.rectangle(frame,(x,y),(x+w,y+h),(0,0,255),2)

逻辑处理 车辆统计

#对车辆的宽高进行判断
#以验证是否是有效的车辆
isValid = (w>=min_w) and (h>=min_h)
if(not isValid):
    continue
#到这里都是有效的车
cv2.rectangle(frame,(x,y),(x+w,y+h),(0,0,255),2)
#取出车的中心点
cpoint = center(x,y,w,h)
cars.append(cpoint)
            
#中心点落在线内,统计
for (x,y) in cars:
#要有一条线,有范围,从数组中减去
	if((y > line_high - offset) and (y < line_high + offset)):
		carno += 1
		cars.remove((x,y))
		print(carno)

显示车辆统计信息

cv2.putText(frame,"Cars Count:" + str(carno),(500,60),cv2.FONT_HERSHEY_SIMPLEX,2,(255,0,0),5)
  • 同时进行线高、偏移等参数,使其检测尽可能准确
  • 后期完善:进行深度学习的数据训练

完整代码

import cv2
import numpy as np

min_w = 90
min_h = 90

#检测线的高度
line_high = 550

#线的偏移
offset = 7

#统计车的数量
carno = 0

#存放有效车辆的数组
cars = []

#获取中心点
def center(x,y,w,h):
    x1 = int(w/2)
    y1 = int(h/2)
    cx = x + x1
    cy = y + y1
    return cx,cy

#加载视频
cap = cv2.VideoCapture('video.mp4')

bgsubmog = cv2.createBackgroundSubtractorMOG()

#形态学kernel
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))

#视频由很多帧组成 循环读取
while True:
    ret, frame = cap.read() #ret读取视频帧是否成功,frame读取视频帧
    if(ret == True):
        #灰度化
        cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
        #高斯去噪点
        blur = cv2.GuassianBlur(frame,(3,3),5)
        #去背景
        mask = bgsubmog.apply(blur)
        
        #腐蚀,去除图中小斑块
        erode = cv2.eroed(mask,kernel)
        #膨胀,还原放大
        dilate = cv2.dilate(erode,kernel,iterations = 3)
        #闭操作,去除物体内部的小块
        close = cv2.morphologyEx(dilate,cv2.MORPH_CLOSE,kernel)
        close = cv2.morphologyEx(close,cv2.MORPH_CLOSE,kernel)
        #绘制轮廓
        cnts, h = cv2.findContours(close,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
        
        cv2.line(frame,(10,line_high),(1200,line_hjgh),(255,255,0),3)
        
        for(i,c) in enumerate(cnts):
            (x,y,w,h) = cv2.boundingRect(c)
            
            #对车辆的宽高进行判断
            #以验证是否是有效的车辆
            isValid = (w>=min_w) and (h>=min_h)
            if(not isValid):
                continue
            #到这里都是有效的车
            cv2.rectangle(frame,(x,y),(x+w,y+h),(0,0,255),2)
            #取出车的中心点
            cpoint = center(x,y,w,h)
            cars.append(cpoint)
            
            #中心点落在线内,统计
            for (x,y) in cars:
                #要有一条线,有范围,从数组中减去
                if((y > line_high - offset) and (y < line_high + offset)):
                    carno += 1
                    cars.remove((x,y))
                    print(carno)
        cv2.putText(frame,"Cars Count:" + str(carno),(500,60),cv2.FONT_HERSHEY_SIMPLEX,2,(255,0,0),5)
        cv2.imshow('video',framw)
        
    key = cv2.waitKey(1)
    if(key == 27): #27为ESC键
        break
#释放资源
cap.release()
cv2.destroyAllWindows()

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

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

相关文章

FastDFS简介/架构/安装/代码

1简介/架构 1.1简单介绍 分布式文件系统&#xff0c;看名字就知道&#xff0c;它可以存储在不同的机器上。肯定也要有路由功能。 特点 备份容错&#xff0c;负载均衡&#xff0c;动态扩容 场景 0-500MB之间大小的文件存储&#xff08;图片&#xff0c;短视频&#xff0c;文…

LeetCode[703]数据流中的第K大元素

难度&#xff1a;简单题目&#xff1a;设计一个找到数据流中第 k大元素的类&#xff08;class&#xff09;。注意是排序后的第 k大元素&#xff0c;不是第 k个不同的元素。描述&#xff1a;请实现 KthLargest类&#xff1a;KthLargest(int k, int[] nums) 使用整数 k 和整数流 …

【北邮果园大三上】数据挖掘

数据挖掘 大数据 定义&#xff1a; 体积时效性种类值 数据挖掘模型 1.归纳已知 2.预测未来 1. 数据的质量处理和度量方法 1.1数据 1.1.1数据属性 属性类型: 标称(nominal)序数(ordinal)区间(interval)比率(ratio) 非对称的属性(asymmetric attribute): 对于非对称的…

airserver怎么下载使用?IOS设备无线传送到Mac电脑的屏幕上教程

AirSever是一种通用的镜像接收器&#xff0c;非常适合镜像iPhone或Android视频文件。 它可以将简单的大屏幕或投影仪变成通用的屏幕镜像接收器。 使用启用了AirSever的设备&#xff0c;您可以用户拥有iPhone&#xff0c;iPad&#xff0c;Mac&#xff0c;Android&#xff0c;Nex…

Proxy详解

Proxy Proxy(代理&#xff09;&#xff0c;首先理解代理是什么意思&#xff0c;才能更便于了解Proxy的作用。 Proxy是一个代理&#xff0c;可以这么理解&#xff0c;就相当于它是一个快递代理点&#xff0c;快递会运输到该代理点&#xff0c;我们取件只需要去对应的代理点取件…

2023年宝塔面板快速部署Rocket.Chat,安卓,PC,ios端使用

官方网站快速部署代码:Docker & Docker Compose - Rocket.Chat Docs 环境:centos 服务器必须大于2核2G,否则docker占用资源太多会起不起来 安装宝塔面板 一 . 宝塔面板安装docker 当然也可以手动安装:如果您还没有&#xff0c;请确保您已安装并运行Docker和Docker-comp…

Docker 数据卷

问题&#xff1a;通过镜像创建一个容器。容器一旦被销毁&#xff0c;则容器内的数据将一并被删除。但有些情况下&#xff0c;通过服务器上传的图片出会丢失。容器中的数据不是持久化状态的。 那有没有一种独立于容器、提供持久化并能服务于多个容器的东西呢&#xff1f; 什么是…

SpringCloud组件之Gateway网关详细教程

目录 一&#xff1a;概念 1.1&#xff1a;什么是微服务网关&#xff1f; 1.2: 为什么需要使用网关&#xff0c;网关的作用&#xff1f; 1.3网关的好处&#xff1f; 二&#xff1a;Gateway网关的快速入门 1.快速创建 2.网关路由的流程 3&#xff1a;Gateway断言工厂 &…

Java复习—运算符

运算符 运算符&#xff1a;对字面量或者变量进行操作的符号 表达式&#xff1a;用运算符把字面量或者变量连接起来&#xff0c;符合Java语法的式子就可以称为表达式。 算数运算符 符号作用加法作用-减法作用*乘法作用/除法法作用%取模、取余 在代码中&#xff0c;如果有小数…

Qt OpenGL(05)标准化设备坐标(NDC)

文章目录OpenGL中的坐标简介标准化设备坐标标准化设备坐标绘制 x y z 三个轴线完整代码顶点着色器片段着色器Widget.hWidget.cpp总结OpenGL中的坐标简介 OpenGL 基于绘制流水线模型&#xff0c;而且绘制流水线的第一个步骤是对顶点进行一 系列的操作, 其中大部分属于几何操作。…

3-2内存管理-虚拟内存

文章目录一.虚拟内存的基本概念二.请求分页管理方式&#xff08;一&#xff09;页表机制&#xff08;二&#xff09;缺页中断机构&#xff08;三&#xff09;地址变换机构三.页面置换算法&#xff08;一&#xff09;最佳置换算法OPT&#xff08;二&#xff09;先进先出页面置换…

flowable 简介

flowable 简介目录概述需求&#xff1a;设计思路实现思路分析1.管理2.二、初识Flowable五大引擎3.2.通过编写程序的方式来构造ProcessEngineConfiguration对象4.流程引擎API架构图5.flowable 表结构说明参考资料和推荐阅读Survive by day and develop by night. talk for impor…

Leetcode_单周赛_327

6283. 正整数和负整数的最大计数 代码 直接遍历统计即可 class Solution {public int maximumCount(int[] nums) {int a 0, b 0;for (int i 0; i < nums.length; i) {if (nums[i] > 0) a;else if (nums[i] < 0) b;}return Math.max(a, b);} }6285. 执行 K 次操作…

Python代码实现:坐标轮换法求解多维最优化问题

文章目录多维最优化问题坐标轮换法原理代码实现坐标轮换法坐标轮换法优缺点多维最优化问题 此前介绍的黄金分割法和切线法都是针对一维最优化问题的解决方案。本文开始&#xff0c;我们将最优化问题从一维扩展到多维&#xff0c;暂时仍考虑无约束的优化场景。 坐标轮换法原理…

ArrayList | 简单的洗牌算法

一个洗牌程序需要包含&#xff1a; 创建一副扑克牌&#xff08;除去大小王剩下52张&#xff0c;每种花色13张&#xff09;。洗牌&#xff0c;打乱牌的顺序。揭牌&#xff0c;每位玩家轮流揭牌&#xff0c;从洗完后的牌组中获得自己的牌。因此&#xff0c;我们可以依照以下思路来…

R 语言 4.2.2安装 WGCNA

文章目录1 WGCNA库介绍2 安装踩坑还得是官方文档这样安装我出现的问题参考AppendixA. 安装RB. 配置环境C. 修改镜像1 WGCNA库介绍 WGCNA是用于加权相关网络分析的R包&#xff0c; 相关网络越来越多地用于生物信息学应用 加权基因共表达网络分析是一种系统生物学方法&#xff0…

按键控制电源通断,实现各种设备/电脑开关机低功耗IC

前言 今天记录一下一些硬件开关电的低功耗控制ic&#xff0c;代替物理机械开关&#xff0c;后续有新的更好用的芯片会继续更新此博。 环境 every machine 参考文档 正文 一版我们选择ic&#xff0c;除了功能之外还要看一些性能&#xff0c;这里我暂时录入的功能就是一个按…

SpringCloud从入门到精通(九)

bus bus-概述 • Spring Cloud Bus 是用轻量的消息中间件将分布式的节点连接起来&#xff0c;可以用于广播配置文件的更改或 者服务的监控管理。关键的思想就是&#xff0c;消息总线可以为微服务做监控&#xff0c;也可以实现应用程序之间相通信。 • Spring Cloud Bus 可选的…

【MySQL】为什么使用B+树做索引

【MySQL】为什么使用B树做索引? 索引这个词&#xff0c;相信大多数人已经相当熟悉了&#xff0c;很多人都知道MySQL的索引主要以B树为主&#xff0c;但是要问到为什么用B树&#xff0c;恐怕很少有人能把前因后果讲述的很完整。本文就来从头到尾介绍下数据库的索引。 索引是一…

linux系统中QT控件的操作的基本方法

大家好&#xff0c;今天主要和大家聊一聊&#xff0c;如何学习QT中的控件使用方法。 目录 第一&#xff1a;QT控件基本简介 第二&#xff1a;QPushButton使用方法 第三&#xff1a;QTableWidget简介 第四&#xff1a;最终运行效果 第一&#xff1a;QT控件基本简介 老子曾说…