2015-09-19 4 views
0

Вопрос похож, но не такой же, как и в Matrix reorganizationРеорганизовать матрица, полученная из PNG изображения с R

У меня есть некоторые 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 - значения для красного, зеленого и синего для этого пикселя, А - альфа (если у него есть изображение).

Я читал о переделке и расплаве, кажется, что это не случай. У меня нет навыков R, чтобы создать функцию mapply для этого. Я бы хотел избежать создания вложенных fors, которые могли бы работать, но были бы неэффективными.

Редактировать массив, кажется, сделать трюк:

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

+0

Пожалуй 'do.call (rbind, lapply (сл (затемнение (myImage) [3]), функция (I) myImage [,, я])) ' – akrun

+2

Сделайте небольшой массив для демонстрационных целей и покажите, каков должен быть результат. Я думаю, что есть очень простое решение (абсолютно нет для циклов), но я хочу проверить его и предоставить тестовый пример - ваша ответственность. (Во-первых, я не понял, что такое «A».) –

+0

@BondedDust Предположительно, A будет каналом альфа (прозрачности) изображения. – WhiteViking

ответ

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). Я предполагаю, что PNG с альфа-каналом будет иметь 4 значения в третьем измерении, поэтому вместо значения hardcoding я отношусь к dim(myImage)[3].

Осталось только изменить имена столбцов (Y, X, R, G, B и, возможно, A) и, при необходимости, переупорядочить строки. Я оставляю их как упражнения для читателя.

+0

Да, это и немного комендантов сделали трюк, я опубликую весь код в ответе ниже. Благодаря! –

1

Это заставляет вас к stucture неопределенно, как желаемый data.frame (хотя заметим, что матрицы R и факторы 1-origined вместо 0-origined:

> 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 было неявно закодировано в слоях, которые были третьим измерением этого массива. У меня есть еще одна работа, которую мне нужно сделать в данный момент, но я вернусь и предоставит более полное решение, если вы или кто-то иначе меня не избивают.

Это должно обеспечить требуемую структуру, за исключением того, что они оставляют X- и Y-столбцы с маркировкой Var1 и Var2 :.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

Используя советы Мирославово, это работает:

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 
Смежные вопросы