Перекрытие скользящего окна поверх изображения с помощью blockproc или im2col?

Мне нужно применить dct2 к маленьким окнам моего изображения, желательно с помощью перекрывающихся окон.

Я обнаружил, что в Matlab есть две функции, которые могут сделать это возможным: blockproc и im2col. У меня тоже проблемы с пониманием, и я был бы признателен за некоторые разъяснения.

blockproc можно использовать для реализации моей функции в скользящем окне с использованием аргументов BorderSize и TrimBorder.

B = blockproc(A,[64,64],fun,'BorderSize',[5,5], 'TrimBorder', 'false');

Я понимаю, что это создает блок [64 + 2*5, 64 + 2*5] и применяет функцию @fun к каждому блоку. Но так как я не могу войти в свою функцию @fun при отладке, чтобы проверить правильность работы, я не могу быть уверен, что это то, что мне нужно. Верен ли мой приведенный выше код для того, что мне нужно? Я знаю, что получаю объединенный результат в B, но он должен быть в перекрывающемся скользящем блоке. Достигнет ли это того, что мне нужно?

Второй im2col. im2col(A,[m n],block_type) разделит блок на m на n блоков и расположит их в столбцах, так что каждый столбец является блоком? Если да, то как контролируется перекрытие? И если каждый блок является столбцом, могу ли я успешно применить функцию dct2 к каждому столбцу? Потому что я сомневаюсь, что он будет принимать векторы в качестве входных данных?

Некоторые разъяснения были бы очень признательны.


person StuckInPhDNoMore    schedule 13.03.2015    source источник


Ответы (1)


Хорошо, это довольно сложный вопрос. Я постараюсь разбить это на отдельные части и отвечу на каждый вопрос отдельно.

Вопрос 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
comment
Большое спасибо @rayryeng за отличное и подробное объяснение. Награда добавлена ​​и предоставлена ​​(когда она станет доступна) за такой подробный и полезный ответ :) - person StuckInPhDNoMore; 16.03.2015
comment
@FarazKhan - О, большое спасибо за награду! Тебе вообще не нужно было! Кстати, это противоречит тому, что я сказал о невозможности использовать blockproc в подходе со скользящим окном с вашим предыдущим вопросом... потому что после того, как я провел некоторые эксперименты, вы, безусловно, можете... вам просто нужно повозиться с параметрами. Это был очень интересный вопрос, и я тоже кое-что узнал из всего этого. Также спасибо за постановку вопроса! - person rayryeng; 16.03.2015
comment
Поиграв с приведенным выше кодом, я считаю, что blockproc дает результат, который не идеален для моего классификатора. Каждый блок должен создавать вектор размером 1x200, но я получаю вектор 1x1600 для меньших блоков. Я обнаружил, что это работа blockproc, поскольку он объединяет результаты 4 блоков, ul_output, ll_output, ur_output, lr_output, поэтому он делит области на более мелкие блоки, а затем объединяет их вместе. Это не будет работать на моем классификаторе. Так как мне нужен вывод каждого блока отдельно. Я попытался изменить настройки внутренних функций, но не смог. - person StuckInPhDNoMore; 17.03.2015
comment
@FarazKhan - Не могли бы вы опубликовать еще один вопрос и более подробно рассказать о том, что вы делаете? Возможно, я смогу вам помочь и ответить на ваши вопросы. - person rayryeng; 17.03.2015
comment
Согласен, много чего нужно было сказать для комментария. Я просто начну новый вопрос :) - person StuckInPhDNoMore; 17.03.2015
comment
@rayryeng Некоторое время назад я разместил вопрос и нашел его похожим на то, что вы объяснили. могу я спросить, делаю ли я ту же ошибку? stackoverflow.com/questions/57407606/ - person Maxxx; 08.08.2019