【25】processing-视频(中文)
视频
Daniel Shiffman
现场视频
既然您已经探索了处理中的静态图像,您就可以继续移动图像,特别是从实时相机 (以及后来录制的电影)。首先,我将介绍导入视频库和使用捕获类显示实时视频的基本步骤。
步骤 1.导入处理视频库。
尽管视频库是由处理基金会开发和维护的,但由于其大小,仍然必须通过贡献管理器单独下载。视频和声音库需要通过库管理器下载。从草图菜单中的 “导入库.” 子菜单中选择 “添加库.”。
安装库后,下一步是在代码中导入库。这是通过选择菜单选项 “草图” → “导入库” → “视频”,或者通过键入以下代码行 (该代码应位于草图的最顶部) 来完成的:
import processing.video.*;
使用 “导入库” 菜单选项只能自动将该行插入代码,因此手动键入完全等效。
步骤 2.声明捕获对象。
您最近已经了解了如何从处理语言 (如 PShape 和 PImage) 中内置的类创建对象。应该注意的是,这两个类都是 processing.core 库的一部分,因此不需要导入语句。Processing.video 库内部有两个有用的类 -- 实时视频的捕获和录制视频的电影。在这一步中,我将声明一个捕获对象。
Capture video;
步骤 3.初始化捕获对象。
捕获对象 “视频” 就像任何其他对象一样 -- 要构造一个对象,你需要使用新的运算符,后跟构造函数。对于捕获对象,此代码通常出现在 setup() 中。
video = new Capture();
上面的代码行缺少构造函数的适当参数。记住,这不是你自己写的课程,所以如果不咨询在线参考,就无法知道括号之间需要什么。
引用将显示有几种方法来调用捕获构造函数。调用构造函数的典型方法是使用三个参数:
void setup() { video = new Capture(this, 320, 240);
}
让我们浏览一下捕获构造函数中使用的参数。
- this: 如果你对这意味着什么感到困惑,你并不孤单。从技术上讲,这是指出现 this 这个词的类的实例。不幸的是,这样的定义很可能会引起头部旋转。更好的思考方式是一种自我参照的陈述。毕竟,如果你需要在你自己的代码中引用你的处理程序呢?你可能会试着说 “我” 或 “我”。嗯,这些词在 Java 中不可用,所以你可以这样说。你把它传递到捕获对象的原因是你告诉它: “嘿,听着,我想做视频捕捉,当相机有新图像时,我想让你提醒这个草图。"
- 320: 幸运的是,第一个论点,这是唯一令人困惑的论点。320 是指摄像机拍摄的视频的宽度。
- 240: 视频的高度。
然而,在某些情况下,上述情况是行不通的。例如,如果您的计算机上连接了多个摄像头,该怎么办?如何选择要捕获的对象?此外,在一些罕见的情况下,您可能还需要指定相机的帧速率。对于这些情况,处理将通过 Capture.list() 为您提供所有可能的相机配置列表。您可以在消息控制台中显示这些内容,例如,通过说:
printArray(Capture.list());
您可以使用这些配置的文本创建捕获对象。例如,在带有内置摄像头的 Mac 上,这可能看起来像:
video = new Capture(this, "name=FaceTime HD Camera (Built-in),size=320x240,fps=30");
Capture.list() 实际上为您提供了一个数组,因此您也可以简单地引用所需配置的索引。
video = new Capture(this, Capture.list()[0]);
步骤 4.开始捕获过程。
一旦相机准备好了,就由你来告诉处理开始捕捉图像。
void setup() { video = new Capture(this, 320, 240); video.start();
}
几乎在每种情况下,您都希望在 setup() 中开始捕获。然而,start() 是它自己的方法,你可以选择,比如说,直到其他时间 (比如按下按钮等) 才开始捕获。)
步骤 5.从相机读取图像。
从相机读取帧有两种策略。我将简要地看这两个,并在本章的其余例子中选择一个。然而,这两种策略都在相同的基本原则下运行: 我只想在可以读取新帧时从相机读取图像。
为了检查图像是否可用,您使用可用函数 (),该函数根据是否存在某些内容返回 true 或 false。如果它在那里,则调用函数 read(),并将来自相机的帧读入内存。您可以在 draw() 循环中一遍又一遍地执行此操作,始终检查是否可以自由读取新图像。
void draw() { if (video.available()) { video.read(); }
}
第二种策略,即 “事件” 方法,需要一个函数,该函数在某个事件 (在这种情况下是相机事件) 发生时执行。每当按下鼠标时,都会执行 mousePressed() 函数。对于视频,您可以选择实现函数 captureEvent(),该函数在捕获事件发生时随时调用,也就是说,相机可以使用新帧。这些事件functions (mousePressed(), keyPressed(), captureEvent(), etc.) 有时被称为 “回调”。顺便说一句,如果你密切关注,这就是适合的地方。捕获对象视频知道通过调用 captureEvent() 来通知此草图,因为您在创建捕获对象视频时向它传递了对此草图的引用。
CaptureEvent () 是一个函数,因此需要生活在自己的块中,在 setup() 和 draw() 之外。
void captureEvent(Capture video) {video.read();
}
你可能会注意到一些关于 captureEvent() 的奇怪的事情。它在定义中包含类型捕获的参数。这对你来说可能是多余的; 毕竟,在这个例子中,我已经有了一个全局变量视频。然而,在你可能有多个捕获设备的情况下,两者都可以使用相同的事件函数,视频库将确保将正确的捕获对象传递给 captureEvent()。
总而言之,每当有要读取的东西时,我想调用函数 read(),我可以通过使用 draw() 中的 available() 手动检查来做到这一点或者允许回调为你处理它-captureEvent()。这允许草图通过从主动画循环中分离出从相机中读取的逻辑来更有效地操作。
步骤 6.显示视频图像。
毫无疑问,这是最简单的部分。您可以将捕获对象视为随时间变化的 PImage,事实上,捕获对象可以以与 PImage 对象相同的方式使用。
image(video, 0, 0);
所有这些都放在下面的代码中:
//步骤 1.导入视频库。
import processing.video.*;
//步骤 2.声明捕获对象。
Capture video;
//步骤 5.当有新图像可用时,从相机读取!
void captureEvent(Capture video) {video.read();
}
void setup() { size(320, 240);// 步骤 3.初始化捕获对象。video = new Capture(this, 320, 240);//步骤 4.开始捕获过程。video.start();
}
//步骤 6.显示图像。
void draw() {
image(video, 0, 0);
}
同样,你可以用 PImage 做任何事情 (调整大小、着色、移动等)。) 你可以用捕获对象做。只要您从该对象中读取 (),视频图像将在您操作时更新。请参见以下示例:
import processing.video.*;
Capture video;
void setup() {size(320, 240); video = new Capture(this, 320, 240); video.start();
}
void captureEvent(Capture video) { video.read();
}
void draw() { background(255); tint(mouseX, mouseY, 255); translate(width/2, height/2); imageMode(CENTER); rotate(PI/4); image(video, 0, 0, mouseX, mouseY);
}
请注意,视频图像可以像 PImage 一样着色。它也可以像 PImage 一样移动、旋转和调整大小。以下是视频图像的 “调整亮度” 示例:
//步骤 1。导入视频库
import processing.video.*;
//步骤 2。声明捕获对象
Capture video;
void setup() { size(320, 240); //步骤 3.通过构造函数初始化捕获对象video = new Capture(this, 320, 240); video.start();
}// 新帧可用时的事件
void captureEvent(Capture video) { // 步骤 4.从相机读取图像。video.read();
}
void draw() {loadPixels();video.loadPixels(); for (int x = 0; x < video.width; x++) { for (int y = 0; y < video.height; y++) { // 从 2D 网格计算 1D 位置int loc = x + y * video.width; // 从像素中获取红色,绿色,蓝色值 float r = red (video.pixels[loc]); float g = green(video.pixels[loc]); float b = blue (video.pixels[loc]); //计算基于接近鼠标来改变亮度的数量 float d = dist(x, y, mouseX, mouseY); float adjustbrightness = map(d, 0, 100, 4, 0); r *= adjustbrightness; g *= adjustbrightness; b *= adjustbrightness; // 约束 RGB 以确保它们在 0-255 颜色范围内r = constrain(r, 0, 255); g = constrain(g, 0, 255); b = constrain(b, 0, 255); // 创建新颜色并在窗口中设置像素 color c = color(r, g, b); pixels[loc] = c; } } updatePixels();
}
录制的视频
显示录制的视频遵循与实时视频相同的结构。Processing 的视频库接受大多数视频文件格式; 有关详细信息,请访问电影参考。
步骤 1.声明影片对象,而不是捕获对象。
Movie movie;
步骤 2.初始化电影对象。
movie = new Movie(this, "testmovie.mov");
唯一必要的参数是这个和电影的文件名,用引号括起来。影片文件应存储在草图的数据目录中。
步骤 3.开始播放电影。
有两个选项,play(),播放电影一次,或 loop(),连续循环。
movie.loop();
步骤 4.从电影中读取帧。
同样,这与捕获相同。您可以检查新帧是否可用,或者使用回调函数。
void draw() { if (movie.available()) { movie.read(); }
}
或者:
void movieEvent(Movie movie) { movie.read();
}
步骤 5.显示影片。
image(movie, 0, 0);
以下代码一起显示了该程序:
import processing.video.*;
//步骤 1。声明电影对象。
Movie movie;
void setup() { size(320, 240); // 步骤 2.初始化电影对象。文件 “testmovie.mo v” 应位于数据文件夹中。movie = new Movie(this, "testmovie.mov"); //步骤 3.开始播放电影。只玩一次 play() 可以用来代替。movie.loop();
}
// 步骤 4.从电影中读取新帧。
void movieEvent(Movie movie) { movie.read();
}
//步骤 5.显示电影。
void draw() {image(movie, 0, 0);
}
尽管处理绝不是显示和操作录制视频的最复杂的环境,但视频库中有一些更高级的功能。有一些函数用于获取视频的持续时间 (以秒为单位的长度),用于加速和减慢,以及跳转到视频中的特定点 (等等)。如果您发现性能缓慢且视频播放不稳定,我建议您尝试 P2D 或 P3D 渲染器。
下面是一个使用 jump() (跳转到视频中的特定点) 和 duration() (以秒为单位返回电影长度) 的示例。在此示例中,如果 mouseX 等于 0,则视频跳到开头。如果 mouseX 等于宽度,它会跳到最后。任何其他值都介于两者之间。Jump () 函数允许您立即跳到视频中的某个时间点。Duration () 以秒为单位返回电影的总长度。
import processing.video.*;
Movie movie;
void setup() {size(200, 200); background(0); movie = new Movie(this, "testmovie.mov");
}
void movieEvent(Movie movie) { movie.read();
}
void draw() { // 鼠标 X 与宽度之比float ratio = mouseX / (float) width; movie.jump(ratio * movie.duration()); image(movie, 0, 0);
}
软件镜像
随着小型摄像机连接到越来越多的个人计算机上,开发实时处理图像的软件变得越来越受欢迎。这些类型的应用有时被称为 “镜像”,因为它们提供了观众图像的数字反射。Processing 广泛的图形函数库及其从相机实时捕获的能力使其成为原型制作和软件镜像实验的绝佳环境。
您可以将基本的图像处理技术应用于视频图像,逐个读取和替换像素。更进一步,您可以读取像素并将颜色应用于屏幕上绘制的形状。
我将从一个以 80 × 60 像素捕获视频并在 640 × 480 窗口上渲染的示例开始。对于视频中的每个像素,我将绘制一个八像素宽八像素高的矩形。
让我们首先编写显示矩形网格的程序。在以下示例中,videoScale 变量存储窗口的像素大小与网格大小的比率,对于每一列和每一行,在 (x,y) 处绘制一个矩形位置按视频尺度缩放和调整大小。
// 网格中每个单元格的大小,窗口大小与视频大小的比率
int videoScale = 8;
// 系统中的列数和行数
int cols, rows;
void setup() { size(640, 480); // 初始化列和行 cols = width/videoScale; rows = height/videoScale;
}
void draw() { // 列的开始循环for (int i = 0; i < cols; i++) { //行的开始循环for (int j = 0; j < rows; j++) { //放大以在 (x,y) 处绘制矩形int x = i*videoScale; int y = j*videoScale; fill(255); stroke(0); rect(x, y, videoScale, videoScale); } }
}
知道我想要八像素宽八像素高的正方形,我可以计算列数为宽度除以八,行数为高度除以八。
- 640/8 = 80 列
- 480/8 = 60 行
我现在可以捕捉到 80 × 60 的视频图像。这很有用,因为与 80 × 60 相比,从相机捕捉 640 × 480 的视频可能会很慢。我只想以草图所需的分辨率捕获颜色信息。
对于第 i 列和第 j 行的每个正方形,我在视频图像中查找像素 (I,j) 的颜色,并相应地对其进行着色。请参阅以下粗体中新零件的示例:
import processing.video.*;
//网格中每个单元格的大小,窗口大小与视频大小的比率
int videoScale = 8;
// 系统中的列数和行数
int cols, rows;
//保持捕获对象的变量
Capture video;
void setup() { size(640, 480); //初始化列和行cols = width/videoScale; rows = height/videoScale; background(0);video = new Capture(this, cols, rows);video.start()
}
// 从相机读取图像
void captureEvent(Capture video) { video.read();
}
void draw() {video.loadPixels(); // 列的开始循环for (int i = 0; i < cols; i++) { // 行的开始循环for (int j = 0; j < rows; j++) { // 你在哪里,像素方面?int x = i*videoScale; int y = j*videoScale;color c = video.pixels[i + j*video.width];fill(c); stroke(0); rect(x, y, videoScale, videoScale); } }
}
如您所见,扩展简单的网格系统以包含视频中的颜色只需要添加一些内容。我必须声明并初始化捕获对象,从中读取,并从像素数组中提取颜色。
也可以应用较少的像素颜色到网格中形状的文字映射。在以下示例中,仅使用黑色和白色。视频中出现较亮像素的方块较大,较暗像素的方块较小。
//视频源中的每个像素绘制为
//尺寸基于亮度的矩形。
import processing.video.*;
// 网格中每个单元的大小
int videoScale = 10;
//系统中的列数和行数
int cols, rows;
// 捕获设备的变量
Capture video;
void setup() { size(640, 480); // 初始化列和行cols = width / videoScale; rows = height / videoScale; // 构造捕获对象 video = new Capture(this, cols, rows); video.start();
}
void captureEvent(Capture video) { video.read();
}
void draw() { background(0);video.loadPixels(); //列的开始循环for (int i = 0; i < cols; i++) { //行的开始循环for (int j = 0; j < rows; j++) { // 你在哪里,像素方面?int x = i*videoScale; int y = j*videoScale; //反转列以使图像恢复正常。int loc = (video.width - i - 1) + j * video.width; color c = video.pixels[loc];//矩形的大小是像素亮度的函数。//亮像素是一个大矩形,暗像素是一个小矩形。float sz = (brightness(c)/255) * videoScale; rectMode(CENTER); fill(255); noStroke(); rect(x + videoScale/2, y + videoScale/2, sz, sz); } }
}
考虑分两个步骤开发软件镜像通常很有用。这也将帮助你超越像素到网格上形状的更明显的映射。
步骤 1.开发一个覆盖整个窗口的有趣模式。
步骤 2.使用视频的像素作为查找表,为该模式着色。
比如说,对于第一步,我编写了一个程序,在窗口周围随意涂鸦一行。这是我的算法,用伪代码写的。
- 从屏幕中心的 (x,y) 位置开始。
- 永远重复以下内容:
—选择一个新的 (x,y),留在窗口内。
—从旧 (x,y) 到新 (x,y) 画一条线。
—保存新的 (x,y)。
// 两个全局变量
float x;
float y;
void setup() { size(320, 240); background(255); // 在中心开始 x 和 y x = width/2; y = height/2;
}
void draw() { float newx = constrain(x + random(-20, 20), 0, width); float newy = constrain(y + random(-20, 20), 0, height); //从 (x,y) 到 (newx,newy) 的行stroke(0); strokeWeight(4); line(x, y, newx, newy); x = newx; y = newy;
}
现在我已经完成了图案生成草图,我可以根据视频图像更改笔画 () 来设置颜色。再次注意以下代码中以粗体添加的新代码行:
import processing.video.*;
//两个全局变量
float x;
float y;
//保持捕获对象的变量。
Capture video;
void setup() { size(320, 240); background(255); // 在中心开始 x 和 yx = width/2; y = height/2;//启动捕获过程video = new Capture(this, width, height); video.start();
}void draw() {video.loadPixels();float newx = constrain(x + random(-20, 20), 0, width); float newy = constrain(y + random(-20, 20), 0, height-1);//找到线的中点int midx = int((newx + x) / 2);int midy = int((newy + y) / 2);// 从视频中选择颜色,反转 xcolor c = video.pixels[(width-1-midx) + midy*video.width];//从 (x,y) 到 (newx,newy) 画一条线stroke(c); strokeWeight(4); line(x, y, newx, newy); // 在 (x,y) 中保存 (newx,newy)x = newx; y = newy;
}void captureEvent(Capture video) { // 从相机读取图像video.read();
}
【25】processing-视频(中文)相关推荐
- 【linux视频教程整套共25个视频】Linux初学者入门教程 .
[linux视频教程整套共25个视频]Linux初学者入门教程 视频内容 1.Linux系统安装(一) 2.Linux系统安装(二) 3.Linux系统安装(三) 4.Linux系统安装(四) 5.远 ...
- [译] PyCon 2018: 玛利亚塔·维加亚 —— 什么是 Python 核心开发者?(附视频中文字幕)...
原视频地址:Mariatta Wijaya - What is a Python Core Developer?- PyCon 2018 译文出自:掘金翻译计划 本文永久链接:github.com/x ...
- 25个视频神同步,还能给视频声音移花接木,谷歌开源最新自监督算法
晓查 发自 凹非寺 量子位 出品 | 公众号 QbitAI 对于AI来说,识别视频里发生了什么已经不是难事,训练它的方法就是用带有标签的视频数据集进行监督学习. 比如我们给AI看带有"棒球& ...
- Linux环境Font font = new Font(“宋体“,Font.PLAIN,25) Graphics.drawString()中文乱码
通过java代码生成图片时,图片上包含中文文字时,在windows环境下正常显示,但是在linux环境中可能出线乱码情况,这是由于您的linux服务器上没有中文字体导致的. 解决方案如下: [1].检 ...
- 班迪(高清录制视频) 中文最新(附带工具)
链接:https://pan.baidu.com/s/1Lg8b85_QYQ92fDtC7S09zA?pwd=6688 提取码:6688
- Learning VR Photography and Video 学习VR摄影和视频 Lynda课程中文字幕
Learning VR Photography and Video 中文字幕 学习VR摄影和视频 中文字幕Learning VR Photography and Video 虚拟现实可以将您穿过城镇或 ...
- Processing如何打包导出中文字体
Processing如何打包导出中文字体 文章目录 Processing如何打包导出中文字体 原理 步骤 用途 原理 使用Processing自带的字体创建工具,创建.vlw字体.该工具为每个char ...
- Processing入门教程-Processing的“前世今生”
很早以前大概13.14年就通过清华大学付志勇教授了解到了Processing这个工具,起初只是初步了解并没有下定决心学习(当初资料太少了).由于当时只是初步的看了看,所以很多内容和知识点都是一知半解的 ...
- Kotlin Weekly 中文周报
Kotlin Weekly 中文周报 -- 25 Kotlin 开发中文周报 文章 使用 Kotlin 中的 takeIf (zhuanlan.zhihu.com) 在 Kotlin 的标准函数中有个 ...
- java qrious 二维码中文无反应_来了来了,今天的苹果限免应用刚刚出炉,8款APP在App Store限时免费啦!手慢无~...
关于iOS限免应用在分享前,得提醒一下大家: 限免应用具有时效性,随时可能恢复到原价,看到喜欢的应用就抓紧时间下载 下载前请仔细核对价格,避免产生不必要的费用 限免应用,你们可以在APP Store( ...
最新文章
- DataFrame的copy的用法
- inline-block元素出现位置错位的解决方法
- Cygwin获取root权限
- foursquare nyc数据集_炫酷的python地理数据可视化
- linux变量最大长度,51CTO博客-专业IT技术博客创作平台-技术成就梦想
- 求职必看!大厂面试中遇到了发散性问题..... ,怎么办?
- JanusGraph
- excel转置怎么操作_Excel拆分文本,想怎么拆就怎么拆,简单易学,一看就会
- html中颜色取样器工具,photoshop基础教程:颜色取样器工具的使用详解
- FitLine+直线拟合+C++
- RabbitMQ总结
- 用物理学分析马歇尔的价格均衡论
- Choerodon前端环境变量方案
- 苹果笔记本python开发第一个程序_Xcode的第一个mac程序
- pythonocc 等步长平分周长的分割曲线
- 网易互娱AI Lab视频动捕技术iCap被CVPR 2022接收!
- 金融大数据分析-Jupyter-Python3-资产定价模型-CAPM
- 接入alipay-sdk
- JiangxiBank
- 非主流茶馆: CIO的八种死法
热门文章
- shel中的if-else语句
- 初学python------写一个心理测试
- Inkscape 输入希腊字母
- 2022-2028年中国高尔夫行业市场现状分析及投资前景评估报告
- 基于MySQL的京东用户行为分析
- 鸿蒙空间命运法则,洪荒之终极人族
- 青年大学习简单窗口使用教程
- Attributes as Operators
- python 三国演义人物出场词频统计
- 电脑哔哩哔哩播放器调整为html5,谷歌浏览器插件哔哩哔哩(Bilibili)播放器扩展Extension for Bilibili Player关闭弹幕、截图、画中画...