如何将 PNG 文件转换为像素矩阵?

How to convert a PNG file in to a matrix of pixels?

我想将 PNG 文件转换为像素矩阵。我试过了

I = imread('d:\image.png'); 

在 matlab 中,我得到 3 个单独的矩阵(R 矩阵、G 矩阵、B 矩阵)。
我想要一个代表图像像素数据的 RBG 矩阵。

由于似乎没有人能够在 Matlab 中完成您想要的操作,我将向您展示如何使用 ImageMagick 进行操作,这样您至少可以继续您正在尝试做的事情。

首先,创建一个 8x4 像素的 PNG 图像,每个像素的 RGB 分量设置为 R=00hex,G=44hex,B=55hex,这样我们就可以玩了。

convert -size 8x4 xc:"#004455" image.png

检查它是否正确,identify

identify image.png 
image.png PNG 8x4 8x4+0+0 8-bit sRGB 2c 276B 0.000u 0:00.000

现在,将图像的通道分离成 RGB,并交换通道 1 和 2,即交换绿色和蓝色通道,留下红色(通道 0)不变,然后重新组合分离的通道并写为原始二进制文件

convert image.png -separate -swap 1,2 -combine RGB:out.raw    

现在查看文件内容,xxd分为三部分:

xxd -g3 -c12 out.raw
0000000: 005544 005544 005544 005544  .UD.UD.UD.UD
000000c: 005544 005544 005544 005544  .UD.UD.UD.UD
0000018: 005544 005544 005544 005544  .UD.UD.UD.UD
0000024: 005544 005544 005544 005544  .UD.UD.UD.UD
0000030: 005544 005544 005544 005544  .UD.UD.UD.UD
000003c: 005544 005544 005544 005544  .UD.UD.UD.UD
0000048: 005544 005544 005544 005544  .UD.UD.UD.UD
0000054: 005544 005544 005544 005544  .UD.UD.UD.UD

您有望看到该文件包含 4 行 8 像素,每行带有 RBG #005544

或者,如果您更喜欢它作为文本:

convert image.png -separate -swap 1,2 -combine out.txt

# ImageMagick pixel enumeration: 8,4,255,srgb
0,0: (0,85,68)  #005544  srgb(0,85,68)
1,0: (0,85,68)  #005544  srgb(0,85,68)
2,0: (0,85,68)  #005544  srgb(0,85,68)
3,0: (0,85,68)  #005544  srgb(0,85,68)
4,0: (0,85,68)  #005544  srgb(0,85,68)
5,0: (0,85,68)  #005544  srgb(0,85,68)
6,0: (0,85,68)  #005544  srgb(0,85,68)
7,0: (0,85,68)  #005544  srgb(0,85,68)
0,1: (0,85,68)  #005544  srgb(0,85,68)
1,1: (0,85,68)  #005544  srgb(0,85,68)
2,1: (0,85,68)  #005544  srgb(0,85,68)
3,1: (0,85,68)  #005544  srgb(0,85,68)
4,1: (0,85,68)  #005544  srgb(0,85,68)
5,1: (0,85,68)  #005544  srgb(0,85,68)
6,1: (0,85,68)  #005544  srgb(0,85,68)
7,1: (0,85,68)  #005544  srgb(0,85,68)
0,2: (0,85,68)  #005544  srgb(0,85,68)
1,2: (0,85,68)  #005544  srgb(0,85,68)
2,2: (0,85,68)  #005544  srgb(0,85,68)
3,2: (0,85,68)  #005544  srgb(0,85,68)
4,2: (0,85,68)  #005544  srgb(0,85,68)
5,2: (0,85,68)  #005544  srgb(0,85,68)
6,2: (0,85,68)  #005544  srgb(0,85,68)
7,2: (0,85,68)  #005544  srgb(0,85,68)
0,3: (0,85,68)  #005544  srgb(0,85,68)
1,3: (0,85,68)  #005544  srgb(0,85,68)
2,3: (0,85,68)  #005544  srgb(0,85,68)
3,3: (0,85,68)  #005544  srgb(0,85,68)
4,3: (0,85,68)  #005544  srgb(0,85,68)
5,3: (0,85,68)  #005544  srgb(0,85,68)
6,3: (0,85,68)  #005544  srgb(0,85,68)
7,3: (0,85,68)  #005544  srgb(0,85,68)

您如何获得 3 个单独的矩阵?

您应该有 1 个矩阵,大小为 MxNx3。如果你想让 3 变成 1,你很可能会丢失信息。您有多种选择,具体取决于您的需要。

其中之一是将 RGB 图像转换为灰度图像,使用 Ig=rgb2gray(I) 即可轻松完成。

另一个,正如@Dan 所建议的,是创建一个索引图像。索引图像具有整数而不是颜色,整数应该是存储真实颜色的字典的索引。你可以做到 [Iind,dict]=rgb2ind(I)。例如,索引图像允许您在较少的内存中存储颜色较少的大图像。

我会把它留在这里,如果这不是你要找的,请告诉我以更新答案以提供更多信息。

表示图像的方式有很多种。直接去option3快速回答,不过我也会在option1和2中说明图片是如何表示的:

为了给出一个非常小的示例,我将使用一个非常简单的图像。蓝色-ish要点:

实际使用的图像是上面显示的要点的缩小版本 (5x5px)。你可以在这里找到它:http://i.imgur.com/QvuBpmI.png

选项 1

如果您使用命令阅读:

>> I = imread('icon-bullet_5x5.png')
I(:,:,1) =
    0    0    0    0    0
    0   15   53   26    0
    0   41   89   59    1
    0   16   36   23    1
    0    0    2    0    0
I(:,:,2) =
    0    0    0    0    0
    0   31  103   54    0
    0   96  187  130    4
    0   46  110   69    2
    0    0    4    0    0
I(:,:,3) =
    0    0    0    0    0
    0   56  163   91    0
    0  167  255  216   13
    0   91  212  133    4
    0    0   12    0    0

你得到一个 uint8 的 3D 矩阵(8 位无符号整数)。矩阵的每个 "slice" 都是红色、蓝色和绿色的比例(比例为 [0 255])。您可以模糊地认识到该值位于矩阵中,就像在图像上一样(中心有一些颜色,外围没有任何颜色。

这可以被视为您所问的 "single RGB" 矩阵(正如安德在他的回答的评论中所讨论的那样,Matlab 处理得很好并且非常方便)。


选项2

这里提出的另一种方法是将其转换为颜色图的索引。如果你这样做:

>> [X,map] = rgb2ind(I,8)
X =
    0    0    0    0    0
    0    2    6    7    0
    0    6    5    3    0
    0    7    4    1    0
    0    0    0    0    0
map =
                         0                         0       0.00392156862745098
        0.0901960784313725         0.270588235294118          0.52156862745098
        0.0588235294117647          0.12156862745098         0.219607843137255
         0.231372549019608         0.509803921568627         0.847058823529412
         0.141176470588235         0.431372549019608         0.831372549019608
         0.349019607843137         0.733333333333333                         1
         0.184313725490196         0.388235294117647         0.647058823529412
        0.0823529411764706         0.196078431372549         0.356862745098039

这代表同一张图片。 map 变量包含定义 8 种不同颜色的 8 个 RGB 三元组的列表(我只选择了 8 种颜色以免示例过载,但地图当然可以定义更多颜色)

X中的值与图像中的位置相同,代表map中的"line number"。本例中的行号从 0 开始。 例如,位置 X(2,2) 处的像素(x=2,y=2,从左,从上)的值为 2,因此该像素的颜色由地图中的第 3 行定义 = > R/G/B = 0.0588235294117647, 0.12156862745098, 0.219607843137255.

注意,此处每种颜色的比例从 01(而不是 [0 255]),但解释是相同的。


选项3

但是,对于您的应用程序,如果您必须与芯片通信,您将无法从 Matlab 矩阵处理中获益,您必须 "serialize" 它。在记忆中,并没有2D、3D甚至更高阶的概念。内存只有一维,一长串地址。只是指针和处理程序的使用给我们留下了更多维度的印象,以便更方便地处理这些数据。

要将其发送到您的芯片,您不需要 "single matrix" 个 RGB 值,而是一个 向量 (单列或单行)。一系列连续的像素信息,以及定义它们在向量中的顺序与它们在矩阵中的位置之间关系的约定(例如,Matlab 将它们排列,从上到下从左到右)

以串行方式表示像素颜色的一种常见方式(但绝对不是唯一方式)是将它们表示为一系列 24 位值。每个 24 位值实际上由 3 个连接的字节(8 位无符号整数)组成,表示 R / G / B。由于 24 位整数不是人类可读的,无法表示颜色,因此通常以十六进制格式表示(当您直接处理微芯片时,这也非常方便)。

Matlab 提供的工具可以帮助您轻松转换。

RGBhex = [ dec2hex(I(:,:,1)) dec2hex(I(:,:,2)) dec2hex(I(:,:,3)) ]  ;
>> RGBhex
RGBhex =
000000
000000
000000
000000
000000
000000
0F1F38
2960A7
102E5B
000000
000000
3567A3
... // and so on

在此表示中,值为 0F1F38 的第 7 个像素具有 Red=0F=15Green=1F=31Blue=0F=56。 如果你从左上角开始按列数像素,他在图像中的位置与我们上面示例的像素相同 x=2,y=2 (from left, from top)

注意:某些格式还包括 Alpha channel 中每个像素的 "transparency"。在这种情况下,它通常与 RGB 三元组连接在一起,每个像素变成一个 32 位(4 字节)的值 Alpha / R / G / B。为了简单起见,我没有在此处包含它。


作为验证,您可以注意到该值与示例 1 中的值相同(该位置的像素显示 15/31/56)。

快速转换还表明这与示例 2 中的 RGB 值相同:

>> uint8([[0.0588235294117647, 0.12156862745098, 0.219607843137255]]*256)
ans =
   15   31   56

如果你不想处理十六进制值而更喜欢字节数组,你也可以简单地reshape原始矩阵:

>> RGBuint = reshape( I , [] , 3 )
RGBuint =
    0    0    0
    0    0    0
    0    0    0
    0    0    0
    0    0    0
    0    0    0
   15   31   56
   41   96  167
   16   46   91
    0    0    0
    ... // and so on

这为您提供了一个整数数组 (uint8)。每个像素的位置与上面的十六进制示例中的规则相同。根据您的芯片是否处理 8/16 或 32 位通信,您可以一个一个地发送字节或将它们连接起来以数据包的形式发送。