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

目录

    • 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.1resizeMaxW = 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 = -1angleDeg = 0rotateRate = 1.0resizeFactor = 0resizeX = 0resizeY = 0testFourPt = FalsewarpIdx = -1printControls()

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

  • 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 -= rotateRateIncif key == ord(keyRotateIncr):if rotateRate < rotateRateMax:rotateRate += rotateRateInctestFourPt = Falseprint("Crop rotated rectangle, rate per frame: {:.1f} degrees".format(rotateRate))elif key == ord(keyResizeInc):resizeFactor += 1if resizeFactor > resizeFactorMax:resizeFactor = 0print("Crop region not resized")else:resizeX = resizeMaxW // resizeFactorresizeY = resizeMaxH // resizeFactorprint("Crop region resized to: ", resizeX, 'x', resizeY)elif key == ord(keyWarpTestCycle):# Disable resizing initiallyresizeFactor = 0warpIdx = (warpIdx + 1) % len(warpList)testFourPt = TruetestDescription = 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 pressif 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 += rotateRaterotatedRect = ((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 framepoints = np.int0(cv2.boxPoints(rotatedRect))cv2.drawContours(frame, [points], 0, (255, 0, 0), 1)# Mark top-left cornercv2.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.hqwc.cn/news/2225.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot + Vue前后端分离项目实战 || 二:Spring Boot后端与数据库连接

系列文章&#xff1a; SpringBoot Vue前后端分离项目实战 || 一&#xff1a;Vue前端设计 SpringBoot Vue前后端分离项目实战 || 二&#xff1a;Spring Boot后端与数据库连接 SpringBoot Vue前后端分离项目实战 || 三&#xff1a;Spring Boot后端与Vue前端连接 SpringBoot V…

ChatGPT: 交互式AI助手为互联网用户带来全新体验

目录 概述&#xff1a; 优势&#xff1a; 挑战&#xff1a; 未来发展方向&#xff1a; 概述&#xff1a; 在当今数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;正以惊人的速度改变着我们的生活方式和体验方式。AI 的应用范围越来越广泛&#xff0c;从语音助手到…

基于uni-app+vue3跨端「h5+小程序+App」仿制chatGPT模板实例

uni-chatgpt 一款uniappvite4uview-plus多端ChatGPT模板实例。 全新首发的一款多端仿制chatgpt智能对话实战项目&#xff0c;基于uniAppVue3PiniauViewUIMarkdownIt等技术开发搭建项目。支持编译到h5小程序APP端&#xff0c;支持markdown语法解析及代码高亮。 功能特点 全屏沉…

BACnet网关如何采集Modbus RTU设备转BACnet IP协议

BACnet标准是针对采暖、通风、空调、制冷控制设备设计的&#xff0c;同时也是为其他楼宇控制系统(例如照明&#xff0c;安保&#xff0c;消防等系统)的集成提供一个基本原则。 本文主要讲述了BACnet网关采集Modbus RTU设备&#xff08;M140T&#xff09;&#xff0c;将Modbus …

CentOS 执行yum命令报错【错误:为仓库 ‘appstream‘ 下载元数据失败: ...】

文章目录 一、遇到问题二、原因分析三、解决问题方案一&#xff1a;更新centos提供的yum源新地址1. yum源仓库配置文件内容2. 更新yum源新地址3. 测试yum安装命令 方案二&#xff1a;更新为 国内的yum源1. 使用 阿里的yum源2. 使用 网易的yum源3. 使用 清华的yum源 四、总结 一…

GPT3学习笔记

GPT-3概述 关于GPT-3的主要事实: 模型分类:GPT-3有8个不同的模型&#xff0c;参数从1.25亿到1750亿不等。 模型大小:最大的GPT-3模型有1750亿参数。这比最大的BERT模型大470倍(3.75亿个参数) 体系结构:GPT-3是一种自回归模型&#xff0c;使用仅有解码器的体系结构。使用下一…

升哲科技受邀出席第十四届夏季达沃斯论坛

6月27日至29日&#xff0c;第十四届夏季达沃斯论坛将在天津举办&#xff0c;国务院总理李强将出席论坛&#xff0c;并在开幕式上发表特别致辞。 升哲科技&#xff08;SENSORO&#xff09;创始人兼CEO赵武阳作为中国新生代商业领袖代表&#xff0c;受邀参加开幕式以及主论坛&am…

#10044 「一本通 2.2 例 2」Power Strings(KMP)(内附封面)

题目描述 原题来自&#xff1a;POJ 2406 给定若干个长度 \le 10^6 的字符串&#xff0c;询问每个字符串最多是由多少个相同的子字符串重复连接而成的。如&#xff1a;ababab 则最多有 3 个 ab 连接而成。 输入格式 输入若干行&#xff0c;每行有一个字符串。特别的&#xf…

MATLAB基础知识

MATLAB 基础知识 MATLAB是一个大型运算平台&#xff0c;参与运算的对象有数据流、信号流、逻辑关系等。如同计算器一样&#xff0c;在MATLAB中数学式的计算是直截了当的。但要了解这个大型计算器的使用方法并合理使用它&#xff0c;就先要了解一些MATLAB的基础知识。本章是整个…

Spring 更简单的读取和存储对象、使用注解存取对象

文章目录 1.前言2.存储 Bean对象2.1 前置任务&#xff1a;配置扫描路径&#xff08;重中之重&#xff09;2.2 添加注解存储 Bean 对象2.2.1 类注解2.2.2 方法注解 Bean 3.获取 Bean对象3.1 属性注入3.2 构造方法注入3.3 Setter 注⼊3.4 三种注释的优缺点3.5 另⼀种注⼊关键字&a…

全志V3S嵌入式驱动开发(spi-nand image制作)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 上一篇文章,我们说到了spi-nor image的制作和输入。相比较spi-nor,spi-nand虽然在稳定性上面差一点,但是价格上面有很大的优势。举例来说,一般32M的spi-nor大约在6-7元左右,但…

SpringBoot 中使用 JWT 案例分享详解

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…