Хорошо, это довольно сложный вопрос. Я постараюсь разбить это на отдельные части и отвечу на каждый вопрос отдельно.
Вопрос 1
blockproc
можно использовать для реализации моей функции в скользящем окне с использованием аргументов BorderSize
и TrimBorder
.
B = blockproc(A,[64,64],fun,'BorderSize',[5,5], 'TrimBorder', 'false');
Я понимаю, что это создает блок [64 + 2*5, 64 + 2*5]
и применяет функцию @fun
к каждому блоку. Но так как я не могу войти в свою функцию @fun
при отладке, чтобы проверить правильность работы, я не могу быть уверен, что это то, что мне нужно. Верен ли мой приведенный выше код для того, что мне нужно? Я знаю, что получаю объединенный результат в B
, но он должен быть в перекрывающемся скользящем блоке. Достигнет ли это того, что мне нужно?
После экспериментов с blockproc
это действительно правильно, когда вы можете использовать его, чтобы заставить работать обработку скользящего соседства. Однако вам понадобится дополнительный флаг, который равен PadPartialBlocks
. Назначение этого флага состоит в том, что если вы извлекаете блок, находящийся на внешних краях изображения, и вы не можете создать блок указанного размера, то этот частичный блок дополняется нулями, чтобы он соответствовал к тому же размеру. Вот небольшой пример, чтобы заставить это работать со скользящими окнами. Предположим, у нас есть такая матрица, что:
>> A = reshape(1:25,5,5)
A =
1 6 11 16 21
2 7 12 17 22
3 8 13 18 23
4 9 14 19 24
5 10 15 20 25
Допустим, мы хотели взять среднее значение каждого перекрывающегося соседства 3 x 3 в приведенной выше матрице и заполнить нулями те элементы, которые выходят за границы матрицы. Вы бы сделали это с blockproc
:
B = blockproc(A, [1 1], @(x) mean(x.data(:)), 'BorderSize', [1 1], 'TrimBorder', false, 'PadPartialBlocks', true);
Важно отметить, что размер блока, который в данном случае равен 1 x 1, и BorderSize
, который также равен 1 x 1, установлены иначе, чем вы ожидаете для блока 3 x 3. Чтобы понять, почему это так, нам нужно немного больше узнать о том, как работает BorderSize
. Для заданного центра блока BorderSize
позволяет захватывать значения/пиксели, выходящие за пределы размеров блока исходного размера. Для тех местоположений, которые выходят за границы матрицы, мы по умолчанию заполним эти местоположения нулями. BorderSize
позволяет нам захватить на 2M + 2N
пикселей больше, где M
и N
— это желаемый размер границы по горизонтали и вертикали. Это позволит нам захватить на M
больше пикселей выше и ниже исходного блока и на N
больше пикселей слева и справа от исходного блока.
Следовательно, для значения 1 в A
, если размер блока равен 1 x 1, это означает, что элемент состоит только из 1, и если наше BorderSize
было 1 x 1. Это означает, что наш последний блок будет:
0 0 0
0 1 6
0 2 7
Поскольку размер нашего блока равен 1, центр следующего блока будет равен 6, и мы получим сетку пикселей 3 x 3 и так далее. Также важно, чтобы TrimBorder
было установлено на false
, чтобы мы могли сохранить те пиксели, которые были изначально захвачены при расширении блока. По умолчанию установлено значение true
. Наконец, PadPartialBlocks
равен true
, чтобы гарантировать, что все блоки имеют одинаковый размер. Когда вы запустите приведенный выше код, мы получим следующий результат:
B =
1.7778 4.3333 7.6667 11.0000 8.4444
3.0000 7.0000 12.0000 17.0000 13.0000
3.6667 8.0000 13.0000 18.0000 13.6667
4.3333 9.0000 14.0000 19.0000 14.3333
3.1111 6.3333 9.6667 13.0000 9.7778
Вы можете убедиться, что мы получаем тот же результат, используя nlfilter
, где мы можем применить среднее значение для 3 x 3 скользящих окрестностей:
C = nlfilter(A, [3 3], @(x) mean(x(:)))
C =
1.7778 4.3333 7.6667 11.0000 8.4444
3.0000 7.0000 12.0000 17.0000 13.0000
3.6667 8.0000 13.0000 18.0000 13.6667
4.3333 9.0000 14.0000 19.0000 14.3333
3.1111 6.3333 9.6667 13.0000 9.7778
Таким образом, если вы хотите правильно использовать blockproc
для операций скольжения, вам нужно быть осторожным с тем, как вы устанавливаете размер блока и размер границы соответственно. В этом случае общее правило заключается в том, чтобы всегда устанавливать размер блока равным 1 x 1 и разрешать BorderSize
указывать размер каждого желаемого блока. В частности, для блока размером K x K
вы должны установить BorderSize
равным floor(K/2) x floor(K/2)
соответственно. Было бы проще, если бы K
было странным.
Например, если вам нужна операция фильтрации среднего значения 5 x 5
на основе скользящего окна, вы должны установить BorderSize
на [2 2]
, как K = 5
и floor(K/2) = 2
. Поэтому вы бы сделали это:
B = blockproc(A, [1 1], @(x) mean(x.data(:)), 'BorderSize', [2 2], 'TrimBorder', false, 'PadPartialBlocks', true)
B =
2.5200 4.5600 7.2000 6.9600 6.1200
3.6000 6.4000 10.0000 9.6000 8.4000
4.8000 8.4000 13.0000 12.4000 10.8000
4.0800 7.0400 10.8000 10.2400 8.8800
3.2400 5.5200 8.4000 7.9200 6.8400
Повторение этого с nlfilter
размером 5 x 5 также дает:
C = nlfilter(A, [5 5], @(x) mean(x(:)))
C =
2.5200 4.5600 7.2000 6.9600 6.1200
3.6000 6.4000 10.0000 9.6000 8.4000
4.8000 8.4000 13.0000 12.4000 10.8000
4.0800 7.0400 10.8000 10.2400 8.8800
3.2400 5.5200 8.4000 7.9200 6.8400
Я проводил некоторые временные тесты, и кажется, что blockproc
, используемый в этом контексте, быстрее, чем nlfilter
.
Вопрос 2
Второй im2col
. im2col(A,[m n],block_type)
разделит блок на m на n блоков и расположит их в столбцах, так что каждый столбец является блоком? Если да, то как контролируется перекрытие? И если каждый блок является столбцом, могу ли я успешно применить функцию dct2
к каждому столбцу? Потому что я сомневаюсь, что он будет принимать векторы в качестве входных данных?
Вы правы в том, что im2col
преобразует каждую окрестность или блок пикселей в один столбец, а объединение этих столбцов формирует выходную матрицу. Вы можете контролировать, перекрываются ли блоки или они различны, с помощью параметра block_type
. Укажите distinct
или sliding
(по умолчанию), чтобы управлять этим. Вы также можете контролировать размер каждого района с помощью m
и n
.
Однако если вашей целью является применение dct2
с выходом im2col
, то вы не получите желаемого. В частности, dct2
учитывает пространственное положение каждой точки данных в ваших 2D-данных и используется как часть преобразования. Благодаря преобразованию каждой окрестности пикселя в один столбец двумерные пространственные отношения, которые изначально существовали для каждого блока, теперь исчезли. dct2
предполагает двумерные пространственные данные, но вместо этого вы указываете одномерные данные. Таким образом, im2col
, вероятно, не то, что вы ищете. Если я правильно понимаю, что вы хотите, вместо этого вы захотите использовать blockproc
.
Надеюсь это поможет!
person
rayryeng
schedule
13.03.2015