0

问题与矩阵重组中的问题相似但不同

我有一些 PNG 文件,想做一些像素分析。使用 png 库,我可以轻松读取图像:

myImage <- readPNG("4colorpattern_15.png",native=FALSE)
str(myImage)

输出是

##  num [1:483, 1:483, 1:3] 0 0 0 0 0 0 0 0 0 0 ...

我想把它重新组织成类似的东西

X Y R G B A
0 0 0 0 0 0 
1 0 0 0 0 0
...

X,Y 是坐标,RGB 是该像素的红色、绿色和蓝色值,A 是 alpha(如果图像有它)。

我一直在阅读有关重塑和融化的内容,但似乎并非如此。我没有 R 技能来设计一个 mapply 函数来做到这一点。我想避免创建可能有效但效率低下的嵌套 fors。

编辑 数组似乎可以解决问题:

nrow  <- dim(myImage)[1]
ncol  <- dim(myImage)[2]
nbands <- dim(myImage)[3]
array(myImage,dim=c(nrow*ncol,nbands))

我仍然需要检查顺序是否正确,但我仍然认为其中一个 apply 函数可以做到。此外,这个解决方案没有给我 X 和 Y 坐标。

编辑 2

我添加了一个非常小的 PNG——它的小点非圆点PNG抱歉,点击它太难了!它是一个 9x4 PNG,具有 3x2 像素的 3x2 图案。顶行颜色为黑色、红色、绿色,底行颜色为蓝色、黄色、洋红色。

从该图像中,我希望得到一个类似于

X Y R G B (no A in this case)
0 0 0 0 0
1 0 0 0 0
2 0 0 0 0
3 0 1 0 0
4 0 1 0 0
5 0 1 0 0
6 0 0 1 0
7 0 0 1 0
8 0 0 1 0
...
0 2 0 0 1
1 2 0 0 1
2 2 0 0 1
3 2 1 1 0
4 2 1 1 0
5 2 1 1 0
6 2 1 0 1
7 2 1 0 1
8 2 1 0 1

(很多省略)

这是图片的放大版本供参考,但结果是基于 9x4 的。

较大的一个

4

3 回答 3

1

这使您模糊地像所需的 data.frame 结构(尽管请注意 R 矩阵和因子是 1 起源而不是 0 起源:

> long_tbl <- as.data.frame.table(myImage)
> long_tbl[1:3] <- lapply(long_tbl[1:3], as.numeric)
> head(long_tbl)
  Var1 Var2 Var3 Freq
1    1    1    1    0
2    2    1    1    0
3    3    1    1    0
4    4    1    1    0
5    1    2    1    0
6    2    2    1    0
> tail(long_tbl)
    Var1 Var2 Var3 Freq
103    3    8    3    1
104    4    8    3    1
105    1    9    3    0
106    2    9    3    0
107    3    9    3    1
108    4    9    3    1

剩下的问题是 RGB 编码被隐式编码在该数组的第三维层中。我目前还有一些其他工作需要做,但如果您或其他人没有击败我,我会回来提供更完整的解决方案。

这应该提供所需的结构,除了留下标记为 Var1 和 Var2: 的 X 和 Y 列。Var3 实际上是一个 RGB 标记:

long3tbl <- cbind(long_tbl[1:2],  #Use the X and Y columns unchanged
                    # Replace with zeros in the rows where not the desired color.
                  with(long_tbl, cbind( R=(Var3==1)*Freq, G=(Var3==2)*Freq, B=(Var3==3)*Freq)))

head(long3tbl)
#=========
  Var1 Var2 R G B
1    1    1 0 0 0
2    2    1 0 0 0
3    3    1 0 0 0
4    4    1 0 0 0
5    1    2 0 0 0
6    2    2 0 0 0
#========
tail(long3tbl)
##++++++++++++
    Var1 Var2 R G B
103    3    8 0 0 1
104    4    8 0 0 1
105    1    9 0 0 0
106    2    9 0 0 0
107    3    9 0 0 1
108    4    9 0 0 1
#======
with(long3tbl, plot(Var1, Var2, col=R))
with(long3tbl, plot(Var1, Var2, col=G))
with(long3tbl, plot(Var1, Var2, col=B))
于 2015-09-19T19:58:49.627 回答
1

这似乎可以解决问题:

matrix(c(unlist(expand.grid(seq_len(dim(myImage)[1]), seq_len(dim(myImage)[2]))),
         as.vector(myImage)),
       ncol=dim(myImage)[3]+2)

这里的关键概念是,在 R 中,所有多维结构都是糖衣向量。

反过来可能更容易理解 - 要创建一个矩阵,R 将获取第一个rows项目并将它们放在第一列;然后下一个rows项目将成为第二列。重复这个过程,直到所有列都被填满或向量用完。对数组中的剩余维度重复此操作。

您可以运行array(1:108, c(4,9,3))以帮助可视化这个想法。

现在让我们分解我提出的解决方案。

as.vector(myImage)

这将以下划线向量形式呈现数组。如果您只关心带有 R、G 和 B 的数据框,您可以使用matrix(as.vector(myImage), ncol=3).

seq_len(dim(myImage)[1])
seq_len(dim(myImage)[2])

这些将创建n连续数字的向量,其中n是数组的第一维和第二维中的项目数。它们不是那么有趣,仅作为以下的输入数据:

expand.grid(...)

这个很有趣。它创建具有作为参数给出的所有级别因素的所有可能组合的数据框。第一个因素变化最快。它将给第一个参数的每个值和第二个参数的第一个值;然后第一个参数的每个值与第二个参数的第二个值;等等。这并非巧合,对应于构成 PNG 数组的第一维和第二维的值!

由于expand.grid给出了数据框并且我们想要向量,因此我将其传递给unlist.

然后我将 X 和 Y 坐标的向量与实际值的向量连接起来。

最后,我将一个向量作为参数传递给matrix并强制 R “包装”它,这样我就得到了 5 列(R、G 和 B 三列,X 和 Y 两列)。我假设带有 alpha 通道的 PNG 在三维上会有 4 个值,所以我指的是dim(myImage)[3]而不是硬编码值。

剩下的唯一事情是更改列的名称(Y、X、R、G、B 和可能的 A),并且可以选择对行进行重新排序。我把它们留给读者练习。

于 2015-09-19T20:42:33.537 回答
0

使用 Miroslav 的提示,这有效:

myImage <- readPNG("origs/small.png",native=FALSE)
arr  <- matrix(c(unlist(expand.grid(seq_len(dim(myImage)[1]), seq_len(dim(myImage)[2]))),
    as.vector(myImage)),
    ncol=dim(myImage)[3]+2)
imFrame <- as.data.frame(arr)
colnames(imFrame) <- c('X','Y','R','G','B')
str(imFrame)
imFrame
于 2015-09-21T15:26:58.370 回答