一步一步学OAK之九:通过OAK相机实现视频帧旋转

news2024/11/24 7:01:44

目录

    • Setup 1: 创建文件
    • Setup 2: 安装依赖
    • Setup 3: 导入需要的包
    • Setup 4: 定义变量
    • Setup 5: 定义旋转矩形的四个顶点坐标
    • Setup 6: 创建pipeline
    • Setup 7: 创建节点
    • Setup 8: 设置属性
    • Setup 9: 建立链接
    • Setup 10: 连接设备并启动管道
    • Setup 11: 创建与DepthAI设备通信的输入队列和输出队列
    • Setup 12:循环监听键盘操作相关代码
    • Setup 13:运行程序

Setup 1: 创建文件

  • 创建新建11-rgb-rotate-warp文件夹
  • 用vscode打开该文件夹
  • 新建一个main.py 文件

Setup 2: 安装依赖

安装依赖前需要先创建和激活虚拟环境,我这里已经创建了虚拟环境OAKenv,在终端中输入cd…退回到OAKenv的根目录,输入 OAKenv\Scripts\activate激活虚拟环境

安装pip依赖项:

pip install numpy opencv-python depthai blobconverter --user

Setup 3: 导入需要的包

在main.py中导入项目需要的包

import depthai as dai
import cv2
import numpy as np

Setup 4: 定义变量

keyRotateDecr = 'z'
keyRotateIncr = 'x'
keyResizeInc = 'v'
keyWarpTestCycle = 'c'
def printControls():
    print("=== Controls:")
    print(keyRotateDecr, "-rotated rectangle crop, decrease rate")
    print(keyRotateIncr, "-rotated rectangle crop, increase rate")
    print(keyWarpTestCycle, "-warp 4-point transform, cycle through modes")
    print(keyResizeInc, "-resize cropped region, or disable resize")
    print("h -print controls (help)")
    
rotateRateMax = 5.0
rotateRateInc = 0.1

resizeMaxW = 800
resizeMaxH = 600
resizeFactorMax = 5

代码比较简单,就不解释了

Setup 5: 定义旋转矩形的四个顶点坐标

P0 = [0, 0]  # top-left
P1 = [1, 0]  # top-right
P2 = [1, 1]  # bottom-right
P3 = [0, 1]  # bottom-left
  • P0表示矩形的左上角顶点,坐标为(0, 0)
  • P1表示矩形的右上角顶点,坐标为(1, 0)
  • P2表示矩形的右下角顶点,坐标为(1, 1)
  • P3表示矩形的左下角顶点,坐标为(0, 1)

这四个顶点按照顺时针顺序排列,并且P0被映射到输出图像的左上角,P1被映射到输出图像的右上角,P2被映射到输出图像的右下角,P3被映射到输出图像的左下角。

warpList = [ 
    [[P0, P1, P2, P3], True, "1. passthrough"],
    [[P3, P0, P1, P2], True, "2. rotate 90"],
    [[P2, P3, P0, P1], True, "3. rotate 180"],
    [[P1, P2, P3, P0], True, "4. rotate 270"],
    [[P1, P0, P3, P2], True, "5. horizontal mirror"],
    [[P3, P2, P1, P0], True, "6. vertical flip"],
    [[[-0.1, -0.1], [1.1, -0.1], [1.1, 1.1], [-0.1, 1.1]], True, "7. add black borders"],
    [[[-0.3, 0], [1, 0], [1.3, 1], [0, 1]], True, "8. parallelogram transform"],
    [[[-0.2, 0], [1.8, 0], [1, 1], [0, 1]], True, "9. trapezoid transform"],
]

定义了一个名为warpList的列表,其中包含了不同的扭曲变换操作。

每个变换操作都是一个列表,包含以下元素:

  • 变换操作的顶点顺序,使用归一化坐标表示。
  • 一个布尔值,表示是否启用运行时边界检查。
  • 描述变换操作的字符串。

这些变换操作包括:

  1. 1. passthrough:顶点顺序为[[P0, P1, P2, P3], True],表示不进行任何变换直接传递图像。
  2. 2. rotate 90:顶点顺序为[[P3, P0, P1, P2], True],表示顺时针旋转90度。
  3. 3. rotate 180:顶点顺序为[[P2, P3, P0, P1], True],表示顺时针旋转180度。
  4. 4. rotate 270:顶点顺序为[[P1, P2, P3, P0], True],表示顺时针旋转270度。
  5. 5. horizontal mirror:顶点顺序为[[P1, P0, P3, P2], True],表示水平镜像变换。
  6. 6. vertical flip:顶点顺序为[[P3, P2, P1, P0], True],表示垂直翻转变换。
  7. 7. add black borders:顶点顺序为[[[-0.1, -0.1], [1.1, -0.1], [1.1, 1.1], [-0.1, 1.1]], True],表示在图像周围添加黑色边框。
  8. 8. parallelogram transform:顶点顺序为[[[-0.3, 0], [1, 0], [1.3, 1], [0, 1]], True],表示平行四边形变换。
  9. 9. trapezoid transform:顶点顺序为[[[-0.2, 0], [1.8, 0], [1, 1], [0, 1]], True],表示梯形变换。

通过使用这个warpList列表,可以在图像处理过程中选择不同的变换操作来实现不同的效果。

Setup 6: 创建pipeline

pipeline = dai.Pipeline()

Setup 7: 创建节点

camRgb = pipeline.createColorCamera()
manip = pipeline.createImageManip()

camOut = pipeline.createXLinkOut()
manipOut = pipeline.createXLinkOut()
manipCfg = pipeline.createXLinkIn()

camOut.setStreamName("preview")
manipOut.setStreamName("manip")
manipCfg.setStreamName("manipCfg")

创建了camRgbmanipcamOutmanipOutmanipCfg等对象,并为它们设置了流名称。

  • camRgb代表创建的彩色相机对象。
  • manip代表创建的图像处理对象。
  • camOut代表创建的输出对象,用于将相机图像流发送到外部。
  • manipOut代表创建的输出对象,用于将处理后的图像流发送到外部。
  • manipCfg代表创建的输入对象,用于接收图像处理的配置信息。

Setup 8: 设置属性

camRgb.setPreviewSize(640, 480)
camRgb.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P)
camRgb.setInterleaved(False)
camRgb.setColorOrder(dai.ColorCameraProperties.ColorOrder.BGR)
manip.setMaxOutputFrameSize(2000 * 1500 * 3)

设置相机和图像处理的相关参数和配置信息:

  • camRgb.setPreviewSize(640, 480)设置相机的预览大小为640x480像素。
  • camRgb.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P)设置相机的分辨率为1080p。
  • camRgb.setInterleaved(False)设置相机输出的图像数据不是交错形式。
  • camRgb.setColorOrder(dai.ColorCameraProperties.ColorOrder.BGR)设置相机输出的颜色顺序为BGR。
  • manip.setMaxOutputFrameSize(2000 * 1500 * 3)设置图像处理的最大输出帧大小。

Setup 9: 建立链接

camRgb.preview.link(camOut.input)
camRgb.preview.link(manip.inputImage)
manip.out.link(manipOut.input)
manipCfg.out.link(manip.inputConfig)

这段代码建立了相机图像流和图像处理流之间的链接:

  • camRgb.preview.link(camOut.input)将相机的预览图像流链接到camOut的输入流。这样可以将相机图像预览发送到外部。
  • camRgb.preview.link(manip.inputImage)将相机的预览图像流链接到manip的输入图像流。这样可以将相机图像数据传递给图像处理模块进行处理。
  • manip.out.link(manipOut.input)将图像处理模块的输出图像流链接到manipOut的输入流。这样可以将处理后的图像数据发送到外部。
  • manipCfg.out.link(manip.inputConfig)将图像处理模块的配置信息输出流链接到manip的输入配置流。这样可以通过manipCfg输入对象向图像处理模块发送配置信息。

Setup 10: 连接设备并启动管道

with dai.Device(pipeline) as device:

Setup 11: 创建与DepthAI设备通信的输入队列和输出队列

    qPreview = device.getOutputQueue(name="preview", maxSize=4)
    qManip = device.getOutputQueue(name="manip", maxSize=4)
    qManipCfg = device.getInputQueue(name="manipCfg")
    
    key = -1
    angleDeg = 0
    rotateRate = 1.0
    resizeFactor = 0
    resizeX = 0
    resizeY = 0
    testFourPt = False
    warpIdx = -1

    printControls()

创建用于接收相机预览和图像处理结果的输出队列以及配置信息的输入队列:

  • qPreview = device.getOutputQueue(name="preview", maxSize=4)创建一个名为preview的输出队列qPreview,用于接收相机预览的图像数据。maxSize=4表示队列最大容量为4帧。
  • qManip = device.getOutputQueue(name="manip", maxSize=4)创建一个名为manip的输出队列qManip,用于接收图像处理的结果。maxSize=4表示队列最大容量为4帧。
  • qManipCfg = device.getInputQueue(name="manipCfg")创建一个名为manipCfg的输入队列qManipCfg,用于接收图像处理的配置信息。

Setup 12:循环监听键盘操作相关代码

    while key != ord('q'):
        if key > 0:
            print("Pressed: ", key)
            if key == ord(keyRotateDecr) or key == ord(keyRotateIncr):
                if key == ord(keyRotateDecr):
                    if rotateRate > -rotateRateMax:
                        rotateRate -= rotateRateInc
                if key == ord(keyRotateIncr):
                    if rotateRate < rotateRateMax:
                        rotateRate += rotateRateInc
                testFourPt = False
                print("Crop rotated rectangle, rate per frame: {:.1f} degrees".format(rotateRate))
            elif key == ord(keyResizeInc):
                resizeFactor += 1
                if resizeFactor > resizeFactorMax:
                    resizeFactor = 0
                    print("Crop region not resized")
                else:
                    resizeX = resizeMaxW // resizeFactor
                    resizeY = resizeMaxH // resizeFactor
                    print("Crop region resized to: ", resizeX, 'x', resizeY)
            elif key == ord(keyWarpTestCycle):
                # Disable resizing initially
                resizeFactor = 0
                warpIdx = (warpIdx + 1) % len(warpList)
                testFourPt = True
                testDescription = warpList[warpIdx][2]
                print("Warp 4-point transform: ", testDescription)
            elif key == ord('h'):
                printControls()

        # Send an updated config with continuous rotate, or after a key press
        if key >= 0 or (not testFourPt and abs(rotateRate) > 0.0001):
            cfg = dai.ImageManipConfig()
            if testFourPt:
                test = warpList[warpIdx]
                points, normalized = test[0], test[1]
                point2fList = []
                for p in points:
                    pt = dai.Point2f()
                    pt.x, pt.y = p[0], p[1]
                    point2fList.append(pt)
                cfg.setWarpTransformFourPoints(point2fList, normalized)
            else:
                angleDeg += rotateRate
                rotatedRect = ((320, 240), (400, 400), angleDeg)
                rr = dai.RotatedRect()
                rr.center.x, rr.center.y = rotatedRect[0]
                rr.size.width, rr.size.height = rotatedRect[1]
                rr.angle = rotatedRect[2]
                cfg.setCropRotatedRect(rr, False)
            if resizeFactor > 0:
                cfg.setResize(resizeX, resizeY)
            # cfg.setWarpBorderFillColor(255, 0, 0)
            # cfg.setWarpBorderReplicatePixels()
            qManipCfg.send(cfg)

        for q in [qPreview, qManip]:
            pkt = q.get()
            name = q.getName()
            shape = (3, pkt.getHeight(), pkt.getWidth())
            frame = pkt.getCvFrame()
            if name == "preview" and not testFourPt:
                # Draw RotatedRect cropped area on input frame
                points = np.int0(cv2.boxPoints(rotatedRect))
                cv2.drawContours(frame, [points], 0, (255, 0, 0), 1)
                # Mark top-left corner
                cv2.circle(frame, tuple(points[1]), 10, (255, 0, 0), 2)
            cv2.imshow(name, frame)
        key = cv2.waitKey(1)

Setup 13:运行程序

在终端中输入如下指令运行程序

python main.py

在这里插入图片描述

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

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

相关文章

C#核心知识回顾——2.拓展方法、运算符重载、分部类、里氏替换

1.拓展方法 为现有非静态变量类型添加新方法 1.提升程序拓展性 2.不需要再对象中重新写方法 3.不需要继承来添加方法 4.为别人封装的类型写额外的方法 特点&#xff1a; 1.一定是写在静态类中 2.一定是个静态函数 3.第一个参数为拓展目标 4.第一个参数用this修饰 /// <sum…

element table表格支持添加编辑校验

实现效果&#xff1a; 将table表格与form表单结合使用 &#xff08;用el-form外层包裹el-table结合rules进行校验&#xff09; 代码实现 <template><div><el-card class"box-card" shadow"never"><div><el-buttonsize"m…

E8-事关明细表里的控件事件绑定、日期的计算、明细表的求和等问题的处理办法

起因 下面的讲述的事情是从开发出差申请流程开始的。涉及的知识点偏多&#xff0c;且得容我慢慢梳理出来。以下篇幅可能会有点儿长&#xff0c;但内容我会争取写得精彩的。 图1 发起表单样式如图1&#xff0c;我想实现的是当修改出发日期或结束日期的时候&#xff0c;自动计算…

并发-synchronized详解

JDK1.6之前的synchronized关键字一来就直接给对象加了一把重量级锁&#xff0c;频繁地在用户态和内核态之间切换&#xff0c;导致性能非常低。为了弥补synchronized的不足&#xff0c;大佬doug lee写了一个AQS框架&#xff0c;用Java语言实现了ReentrantLock。然后在JDK1.6之后…

电脑文件夹怎么设置密码?3个方法为文件加密!

我的电脑里存了很多重要的文件夹&#xff0c;为了防止信息的泄露&#xff0c;我想把这些文件夹都设置密码。但是不知道具体应该如何操作。请求大家的帮助&#xff01; 我们平常在使用电脑时&#xff0c;可能会将很多重要的文件保存在电脑中。如果不想让别人看到我们这些重要的文…

JMeter安装RabbitMQ测试插件

目录 前言&#xff1a; 具体实现步骤&#xff1a; 1、ant环境搭建 2、AMQP源码下载 3、拷贝JMeter_core.jar包到JMeter-Rabbit-AMQP插件根目录下 4、修改AMQP插件的配置文件 5、打包 6、RabbitMQ客户端插件下载 7、完成以上&#xff0c;重启JMeter创建线程组就可以看到…

智能小家电如何升级Type-C接口充电?

目前市面上智能小家电充电接口还是USB Micor&#xff0c;AC&#xff0c;DC接口等&#xff0c;今年随着欧盟的一纸令下&#xff0c;22年12月24日&#xff0c;欧洲理事会最终批准了“在欧盟范围内统一充电器接口”的法案。这意味着到2024年&#xff0c;usb type-c接口将成为一系列…

openknx初编译

knx协议出来也是很长时间了&#xff0c;但国内相关开发的文章很少&#xff0c;比起zigbee,lora这些网上一搜一大零的&#xff0c;显得可怜。因为公司以后可能会开发knx产品&#xff0c;所以对国外的openknx自已研究了一下。 https://github.com/thelsing/knx 这个就是openknx项…

Openlayers实战,Openlayers调整地图可视范围到多个点组成的多边形边界,可视范围缩放到多个点的中心点

专栏目录: OpenLayers入门教程汇总目录 前言 本片文章详细讲解如何使用Openlayers调整地图可视范围到多个点组成的多边形边界。 也即Openlayers根据多个点坐标生成一个矩形可视范围,并判断当前传入的矩形可视范围是否在当前可视范围内。如果在当前可视范围内,则调整地图中…

latex中两种图并排放,而且各自有小标题caption

\begin{figure*}[htbp] \centering #小标题 \subfigure[Case study in terms of interpretability on dataset HDep3.]{ \begin{minipage}[t]{0.37\linewidth} %linewidth小于0.5 \centering \includegraphics[scale0.2]{figures/hdep3d.png} #大小主要调节scale. %\caption{fi…

Blazor前后端框架Known-V1.2.1

V1.2.1 Known是基于C#和Blazor开发的前后端分离快速开发框架&#xff0c;开箱即用&#xff0c;跨平台&#xff0c;一处代码&#xff0c;多处运行。 概述 基于C#和Blazor实现的快速开发框架&#xff0c;前后端分离&#xff0c;开箱即用。跨平台&#xff0c;单页应用&#xff…

耳挂式骨传导耳机哪个牌子好,分享几个品牌的骨传导耳机

骨传导耳机就是利用震动来传递声音的耳机&#xff0c;在运动时佩戴骨传导耳机&#xff0c;可以听歌也能听周围的声音&#xff0c;提高了运动时的安全性。目前市面上的骨传导耳机也是琳琅满目。今天就来给大家分享下目前市面上比较常见的几款骨传导耳机。希望对正在选购骨传导耳…

Linux v4l2框架分析

1. 概述 V4L2(Video for Linux 2)&#xff1a;Linux内核中关于视频设备驱动的框架&#xff0c;对上向应用层提供统一的接口&#xff0c;对下支持各类复杂硬件的灵活扩展&#xff1b; V4L2框架&#xff0c;主要包括v4l2-core、meida framework、videobuf2等模块&#xff0c;这也…

120.【ElastiSearch】

ElasticSearch-初级 (一)、什么是ElasticSearch(库、表、记录)1.ElasticSearch是什么2.ElasticSearch学习路线3.聊聊Doug Cutting4.Lucene 和 ElasticSearch的关系: (二)、ElasticSearch概述1.基本概述2.百度搜索关键字思考3.目前都有哪些公司在用ElasticSearch技术 (三)、ES和…

检验样本是否服从泊松分布

本文以一个订单数据为例&#xff0c;研究顾客购买次数的分布规律&#xff0c;尝试从中估计总体的分布&#xff0c;以对后续的订单数据进行预测或进行业绩的对比。 # 环境准备 import numpy as np import pandas as pd import scipy.stats as stats import matplotlib.pyplot a…

Nginx(3)nginx的Rewrite功能

nginx跨域 Rewrite功能配置Rewrite的相关命令Rewrite的案例域名跳转域名镜像独立域名目录自动添加/合并目录防盗链 Rewrite功能配置 Rewrite是Nginx服务器提供的一个重要基本功能&#xff0c;是Web服务器产品中几乎必备的功能。主要的作用是用来实现URL的重写。 注意:Nginx服…

AI生成图片检测器接口,应用于内容审核、虚拟现实应用和促进艺术及设计领域创新等场景

【检测率99.0%以上】可以快速准确地判断一张图片是否为AI生成&#xff0c;减少人工审核的工作量&#xff0c;提高工作效率、降低运营成本&#xff0c;帮助人们更好地管理和利用数字图像资源。广泛应用于内容审核、虚拟现实应用和促进艺术及设计领域创新等场景。 一、效果展示 …

Unity学习笔记--EventSystem事件系统在使用上需要注意的地方(很基础,但是很多人会忘记!!!)

目录 前言代码Unity 场景配置运行报错分析解决办法拓展&#xff08;预告&#xff09; 前言 之前有写过一篇关于事件系统实现以及使用的文章 Unity学习笔记–C#事件系统的实现与应用 最近在使用的时候遇到了一些问题&#xff0c;所以在此记录下&#xff0c;也为看到这篇文章的人…

魏副业而战:视频带货借助热点,这个账号月赚20w+

我是魏哥&#xff0c;与其在家躺平&#xff0c;不如魏副业而战&#xff01; 最近魏哥一直在研究短视频&#xff0c;每天刷刷抖音&#xff0c;经常刷到高考相关的视频。 本来高考跟我没关&#xff0c;毕竟孩子还小&#xff0c;但是刷得多了&#xff0c;魏哥发现有情况。 像这个…

oneAPI人工智能分析工具包实现图像处理

文章目录 一、oneAPI的介绍二、oneAPI实现图像处理环境配置加载预训练模型和网络创建IECore对象和设备插件准备输入数据执行推理总结 一、oneAPI的介绍 oneAPI是一个由英特尔&#xff08;Intel&#xff09;主导的、面向异构计算的开放标准和平台。它旨在简化和加速跨多种硬件架…