什么是矩阵?
本教程讲解处理矩阵数据的方法。可以先回顾一下 Max/MSP/Jitter 教程 01 - 什么是矩阵?
矩阵用虚拟的网格来存储和修改大批的数值数据。数据存储在矩阵中,就可以通过网格位置查找,并指定整个矩阵或部分矩阵来批量修改多个值。
在上一篇教程中,我们使用 jit.window
对象打开一个窗口,并将矩阵的内容显示为彩色像素。
显示的矩阵来自 jit.movie
对象,它用 QuickTime 视频的当前帧连续填充矩阵。jit.window
之所以能显示视频,只不过因为被告知要显示哪些矩阵的内容; 事实上,矩阵中的任何数值都可以显示。本教程通过一个更简单的例子帮助你理解矩阵,它是 Jitter 的核心思想。
以下是本节完整的 patcher 截图
jit.matrix 对象
为单个 8 位值创建 16x12 存储空间
jit.matrix
对象创建矩阵并在内存中声明存储空间,以便我们存储和检索数值,并打印或显示出来。 jit.matrix
的参数包括:
[name](可选,本例中未包含)
[planecount](在矩阵的每个单元格中存储多少个值)
[type](用多少个字节来表示每个数字)
[dim](维度,描述矩阵的大小)
括号 [] 里面应填入实际的赋值。上面的例子创建了 1 个平面(每个矩阵单元包含 1 个数字)、尺寸为 16x12(共 192 个单元格)的 char 型(单字节值)矩阵。由此可以推断出矩阵能够保存 192 个单独的数值,每个值的范围是 0~255(单个字节的范围)。
注意:在 Max 中用 x,y(宽度,高度)格式描述二维矩阵的维数,先给出水平维度的范围,然后是垂直维度。这跟视频和计算机屏幕坐标处理尺寸的方式一致(例如,640x480 视频图像)。即,先说明有多少列(宽),再说明有多少行(高)。需要注意,Jitter 描述行和列,与线性代数中描述矩阵的惯例(先表示行,然后是列)不同。
回到例子中,一个按钮连接到 jit.matrix
的入口。当 Jitter 对象在左入口接收到 bang
消息时会发送矩阵名称,这个按钮会触发 jit.matrix
发送它的矩阵名称(以 jit_matrix
消息的形式)。
jit.print对象
打印 ``jit.matrix`` 的内容
在 jit.matrix
下面有一个新的 Jitter 对象:jit.print
。它在入口处接收矩阵名称(jit_matrix
消息)并格式化矩阵的值,以便在 Max Console 中打印。它将格式化的值打印到 Max Console,就像 Max 的 print
对象一样,然后在 jit_matrix
消息中以矩阵名称的形式传递出来。
单击标记为 “output” 的按钮,这会让 jit.matrix
传递矩阵名称给 jit.print
,后者格式化值并在 Max Console 中显示:jit_matrix [somename]
。左边的单词表示这是由 jit.print
对象打印的,这是 jit.matrix
出口的结果。
因为我们没有指定矩阵的名称(没有指定 jit.matrix
的第一个输入参数),所以 jit.matrix
自己会生成唯一名称(类似 “u330000007”)。这里我们并不关心名称是什么,但它能够告诉 jit.print
对象要显示哪个矩阵的数据。
上图显示了来自 jit.print
矩阵中的所有值,按 16 列和 12 行整齐排列。它们现在都是 0,因为我们还没有在矩阵中填充任何内容。
在矩阵中设置和查询值
在上一章中,我们知道如何使用 QuickTime 视频中的彩色数据帧自动填充整个矩阵。还可以将数值放置在矩阵的特定单元格中,并从特定位置检索。
在下面的例子中,jit.matrix
上方有一些消息框,可以设置和获取矩阵中的值。
消息 setcell 和 getcell 可以访问矩阵中的特定值
使用 setcell
消息可以在特定的矩阵位置中存储值。语法是: setcell [cell coordinates] val [value(s)]
。
例如, jit.matrix
消息 setcell 0 0 val 127
会将矩阵的第一个单元格(即左上角的单元格)的值设置为 127。每个维度中对单元格坐标的编号从 0 开始,最大值比维度小 1。在此矩阵中,x 维度中的位置编号为 0~15,y 维度中的位置编号为 0~11。因此右下角的单元格坐标是 15 11.
pack 0 0 0
对象组合多个数字提供给setcell
消息发送给 jit.matrix
。首先设置想要存储值的 x 和 y 位置,然后指定要存储在那里的值。当 x 和 y 位置为 0 0 时,用标有“value” 的数字框发送 127 到 pack 0 0 0
的左侧入口。这将触发消息 setcell 0 0 val 127
发送给 jit.matrix
。
消息 ``setcell 0 0 val 127`` 设置单元位置 0,0 的值为 127
(如果矩阵中有多个平面,可以在单元格的特定/所有平面中设置值)
为了演示之前提过的单元格位置编号,现在尝试将消息 setcell 15 11 val 255
发送到 jit.matrix
。在 “X position” 下面的数字框输入 15,在 “Y position” 下面的数字框输入 11 ,在 “value” 下面的数字框输入 255。然后点击 “output” 按钮查看矩阵的变化。jit.print
在 Max 控制台中打印出整个矩阵。请注意,单元格位置 0,0 和 15,11 中的值已变为 127 和 255。
消息 ``setcell 15 11 val 255``将单元格位置 15,11 的值设置为 255
在 Patch 窗口中,你可能已经注意到黑色矩形区域的变化。它的左上角和右下角已经改变了。
``jit.pwindow`` 对象显示的数值为颜色(或灰度值)
该区域是一个名为 jit.pwindow
的用户界面对象。在添加对象面板中可以找到它:
对象选项板中的 ``jit.pwindow`` 图标
在添加对象面板中单击或将其拖动到 patch 窗口时,它会创建一个小的矩形对象(可以拖动对象右下角调整尺寸)。它在功能上与 jit.window
非常相似,区别是它在 Patch 窗口中显示矩阵数据,而不是在一个单独的窗口。
于是我们看到数值显示为颜色(char 数值范围是 0~255)。矩阵中只有一个平面,所以是单色(即灰度)。0 表示黑色,其他值是某种灰度,最大值255 是白色。因此,单元格 15,11 的 255 值显示为白色,0,0 的 127 值显示为黑色和白色之间的 50% 灰色。
你可能会觉得这样填充矩阵相当繁琐。没错。所以 Max 允许我们编写程序来自动填充。
以算法方式填充矩阵
双击 patcher fillmatrix
对象打开子 patch。它将不同的数字传入数学表达式,生成 192 个不同的值到矩阵中的每个单元。
通过算法生成值来填充矩阵的单元格
当 uzi 12
对象收到 bang
(点击主 Patch 窗口中标记为 “fill” 的按钮)时,它会快速从右侧出口进行 1 到 12 计数,并向左侧出口发送每个计数的 bang。
那些 bang 触发了uzi 16
对象,因此它每次都会发出 1~16 的数字。然后把这些数字减去 1,这样值的范围就限定在 0~11 和 0~15,输出的结果作为矩阵中的 y 和 x 位置。对于 12 个 y 位置中的每一个,uzi 16
对象指定所有 x 位置,然后在数学表达式(expr)中使用这些数字来计算要存储在该位置的值。这些数字从 outlet 发送给主 patch 创建定义好的 setcell
消息,就像我们之前手动做的那样。
这里不需要关注具体的数学表达式。它可以生成任何公式。刚才我们用一个公式在每列中产生亮度的正弦梯度,这将让列的整体亮度从左向右增加(即随 x 增加)。
关闭 patcher fillmatrix
,然后单击标记为 “fill” 的按钮。矩阵在 Max 的 scheduler 的每个时钟节拍中填充值(由子 patch 中的 uzi 对象生成)。现在单击标有 “output” 的按钮查看矩阵的内容。数值将打印在 Max Console 中,并显示在 jit.pwindow
中。
即使对于像 16x12 这样的小型矩阵,仅仅查看 Max Console 中的数字打印输出,我们很难看到数值数据的趋势。而 jit.pwindow
中的显示能够清楚而直观地展示值在矩阵中的变化情况。这是数据可视化的好处。
output display.png
你可以想象在 Max 中以算法方式填充矩阵的其他方法,我们将在后面的教程中演示。
jit.matrix 可以响应的其他消息
jit.matrix
还可以接收许多其他消息。例如可以使用相同的值填充所有 jit.matrix
。发送给jit.matrix
的 clear
消息将所有值设置为 0,setall
消息(setall 后跟一个值)将矩阵中的所有单元设置为同一个值。
查询矩阵位置 8,6 处的值; 报告单元格 8 6 val [value(s)]
还有 getcell
消息。单词 getcell
后跟矩阵中的位置(x和y)会让 jit.matrix
将单元格坐标和该位置的值发送到右侧出口。
在 getcell $1 $2
消息框上方的数字框中输入 y 值,然后输入 x 值,并观察 Max Console 中打印的内容。请注意,该矩阵位置的值在 jit.matrix
的右侧出口输出。
在后面的教程中,你将看到从矩阵中检索值的各种方法。
小结
jit.matrix
对象可以为任何尺寸、平面数和数据类型的矩阵数据创建存储空间。该矩阵可以填充来自另一个 Jitter 对象(例如 jit.movie
)的数据,或者用 setall [value]
之类的消息来设置所有单元格中的值,或者 setcell [position] val [value(s)]
来设置特定单元。可以使用 patch 中其他位置的算法根据公式或一组规则来填充矩阵。
要获取特定单元格中的数据,可以使用 getcell [position]
消息。要查看在 Max Console 中打印的所有数值数据,请使用 jit.print
对象格式化矩阵数据并打印。要查看显示为颜色的矩阵数据,请使用 jit.pwindow
对象。这类似于教程1中演示的 jit.window
对象。
在本教程中,我们查看了自己生成的数据,而不是上一篇中的数字视频。两种情况下的存储原理是相同的。无论矩阵是存储来自数字视频帧的每个像素的颜色信息,还是表示颜色的数字,它们都存储在二维矩阵中,并且通过 jit.window
或 jit.pwindow
显示。
作者:Kidult
链接:https://www.jianshu.com/p/5b489de527ee
共同学习,写下你的评论
评论加载中...
作者其他优质文章