首页 文章

用R重新组织从PNG图像获得的矩阵

提问于
浏览
0

问题类似但与Matrix reorganization中的不一样

我有一些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 .

Edit 数组似乎可以解决问题:

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

我仍然需要检查订单是否正确,但我仍然认为其中一个应用功能可以做到 . 此外,这个解决方案没有给我X和Y坐标 .

Edit 2

我添加了一个非常小的PNG
Itsy bitsy non-polka-dotted 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图像 .

Larger one

3 回答

  • 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到"wrap"它因此我得到5列(R,G和B三个,X和Y加两个) . 我假设带有alpha通道的PNG在第三维中将有4个值,所以我指的是 dim(myImage)[3] 而不是硬编码值 .

    唯一剩下的就是更改列的名称(Y,X,R,G,B和可能的A)以及可选的重新排序行 . 我把它们作为读者练习 .

  • 1

    这会让你的结构模糊地像所需的data.frame(虽然注意到R矩阵和因子是1-origin而不是0-origin:

    > 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))
    
  • 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
    

相关问题