Как произвольно извлечь определенное подмножество изображений из набора данных?

Недавно я планирую манипулировать стеком изображений, и цель состоит в том, чтобы извлечь оттуда определенное подмножество срезов, например только четные или нечетные или произвольные индексы, а затем сохранить их в другой набор данных.

В DM есть ряд полезных функций в меню Громкость, но, к сожалению, они не могут полностью реализовать то, что я хочу сделать.

Мне просто интересно, можно ли реализовать эту идею с помощью сценариев.

Большое спасибо за вашу помощь заранее.


person DM Adventurer    schedule 04.05.2018    source источник
comment
Я предлагаю вам опубликовать исходное решение кода по вашему вопросу. Большинство пользователей SO попросят вас показать, что вы приложили некоторые усилия для самостоятельного решения своего вопроса. Кроме того, это значительно упрощает помощь в решении вашего вопроса. Удачи и добро пожаловать в Stackoverflow.   -  person Rann Lifshitz    schedule 04.05.2018
comment
Добро пожаловать в СО. Это очень хороший вопрос для начала использования сценария DM в качестве инструмента анализа данных, поэтому я дал более развернутый ответ, чем необходимо, чтобы иметь ссылку для людей. Ответ quick таков: все функции меню Громкость легко воспроизводятся с помощью очень небольшого количества строк кода с использованием команды SliceN, как описано в нижней части моего ответа.   -  person BmyGuest    schedule 04.05.2018
comment
У вас прекрасный юзер-имидж ;c)   -  person BmyGuest    schedule 04.05.2018


Ответы (1)


Есть два способа сделать это, один из них подходит только для данных до 3D и, как правило, медленнее, чем другой, но более гибкий. Поскольку вы просили об произвольной субдискретизации, я начну с этого варианта, но более вероятно, что второй вариант даст вам то, что вы хотите: ортогональная, регулярная субдискретизация .

Если вы спешите, краткий ответ: Используйте команду SliceN.


1) Использование выражений (произвольная подвыборка)

Отдельные позиции пикселей в данных Image (img) можно адресовать с помощью обозначений

  • img[ X, 0 ] ... для 1D-данных в позиции X
  • img[ X, Y ] ... для 2D-данных в позиции X/Y
  • img[ X, Y, Z ] ... для 3D-данных в позиции X/Y/Z

Обратите внимание, что даже если это относится к одному числу, результатом будет выражение размера 1x1 или 1x1x1, а не скалярное число, поэтому вы < strong>не могу сделать: number num = img[10,4]

Однако вы можете использовать небольшую хитрость, чтобы использовать любую из функций, которые преобразуют выражение в одно число, например, f.e. суммирование. Итак, вы можете сделать: number num = sum(img[10,4])

Так как это относится к вашему вопросу? Что ж, в приведенных выше выражениях мы использовали скалярные значения как X, Y и Z, а полученные выражения были выражениями размера 1x1 и 1x1x1, но

Вы можете использовать выражения любого размера как X, Y, Z в этих обозначениях, если все они являются выражениями одного и того же размера. Результирующие адресуемые данные имеют этот размер со ссылками на значения по соответствующим координатам.

Это станет яснее с приведенными ниже примерами. Начнем с простого примера 1D:

image img1D := RealImage( "TestData", 4, 100 )
image coord := RealImage( "Coordinates", 4, 10 )

img1D = 1000 + icol             // Just sum test data
coord = trunc(100*Random())     // random integer 0-99
image subImg :=  img1D[coord,0]

img1D.ShowImage()
coord.ShowImage()
subImg.ShowImage()

Пример произвольной подвыборки 1D

Наши тестовые данные (img1D) здесь представляют собой просто линейный график от 1000 до 1099 с использованием выражения icol, которое для каждого пикселя представляет координату X этого пикселя.

Изображение координат (coord) содержит случайные целые числа от 0 до 99.

«Волшебство» происходит в subImg. Мы используем выражение с изображением coord в качестве координат X. Это изображение имеет размер 10(x1), поэтому результирующее выражение имеет размер 10(x1), который мы присваиваем изображению subImg перед его отображением.

Обратите внимание, что построенное нами выражение на самом деле просто указывает на эти данные изображения. Вместо того, чтобы показывать его как новое изображение, мы могли бы использовать это выражение для изменения этих точек в данных, используя:

img1D[coord,0] = 0

Пример установки данных по выражению


Взяв его отсюда, можно прямо расширить пример до 2D:

image img2D := RealImage( "TestData", 4, 30, 30 )
image coordX := RealImage( "Coordinates X", 4, 10 )
image coordY := RealImage( "Coordinates Y", 4, 10 )

img2D = 10000 + icol + irow * 100
coordX = trunc(30*Random())
coordY = trunc(30*Random())
img2D[coordX,coordY] = 0

coordX.ShowImage()
coordY.ShowImage()
img2D.ShowImage()

Пример для 2D


...и 3D:

image img3D := RealImage( "TestData", 4, 30, 30, 30 )
image coordX := RealImage( "Coordinates X", 4, 10 )
image coordY := RealImage( "Coordinates Y", 4, 10 )
image coordZ := RealImage( "Coordinates Y", 4, 10 )

img3D = 10000 + icol + irow * 100 + iplane * 1000
coordX = trunc(30*Random())
coordY = trunc(30*Random())
coordZ = trunc(30*Random())
img3D[coordX,coordY,coordZ] = 0

coordX.ShowImage()
coordY.ShowImage()
coordZ.ShowImage()
img3D.ShowImage()

К сожалению, это заканчивается здесь.

Вы больше не можете использовать этот тип адресации в данных 4D или 5D, потому что выражение с 4 параметрами уже определено для адресации прямоугольной области в данных 2D как img[T,L,B,R]



2) Использование SliceN (ортогональная субдискретизация)

Подмножества данных вдоль направлений измерения данных могут быть адресованы с помощью команды SliceN и ее упрощенных вариантов Slice1, Slice2 и Slice3.

Команда SliceN, пожалуй, одна из моих любимых команд языка при работе с данными. Сначала это выглядит пугающе, но это прямолинейно.

Давайте начнем с его упрощенной версии для извлечения 1D, Slice1.

Чтобы извлечь 1D-данные из любых данных вплоть до 3D с помощью команды Slice1, вам необходимо следующее (и это ровно 7 параметров, используемых командой-):

  • источник данных
  • начальная точка в источнике
  • направление отбора проб
  • длина выборки
  • размер шага выборки

Единственное, что вам нужно знать вдобавок к этому:

  • Начальная точка всегда определяется как триплет X,Y,Z, даже если источником данных является только 2D или 1D.
    0 используется для ненужных измерений.
  • Направления указаны в виде индекса измерения: 0 = X, 1 = Y, 2 = Z
  • Размер шага может быть отрицательным, чтобы указать противоположные направления.
  • Указанная выборка должна содержаться в исходных данных.
    (Вы не можете "экстраполировать").

Таким образом, очень простым примером извлечения 1D-данных из набора 3D-данных будет:

number sx = 20
number sy = 20
number sz = 20

image img3D := RealImage( "Spectrum Image", 4, sx, sy, sz )
img3D = 5000000 + icol + irow * 100 + iplane * 10000

number px = 5
number py = 7
image spec1D := Slice1( img3D, px,py,0, 2,sz,1 )

ShowImage( img3D )
ShowImage( spec1D )

Этот пример демонстрирует довольно типичную ситуацию в аналитической микроскопии при работе с данными «3D Spectrum Image»: Извлечение «1D Spectrum» в определенном пространственном положении.

В примере это было сделано для пространственной точки px,py. Начиная с точки в этой позиции (px,py,0), выполняется выборка по направлению Z (2) для всех пикселей данных (sz) с размером шага 1.

Обратите внимание, что команда снова возвращает выражение в исходных данных, и что вы также можете использовать это для установки значений, просто используя f.e.:

Slice1( img3D, px,py,0, 2,sz,1 ) = 0


Расширение для 2D- и 3D-данных с помощью команд Slice2 и Slice3 осуществляется напрямую. Вместо определения одного направления вывода вы определяете два или три соответственно. Каждый с тройкой чисел: направление, длина, размер шага.

В следующем примере извлекается «плоскость изображения» из «изображения 3D Spectrum»:

number sx = 20
number sy = 20
number sz = 20

image img3D := RealImage( "Spectrum Image", 4, sx, sy, sz )
img3D = 5000000 + icol + irow * 100 + iplane * 10000

number pz = 3
image plane2D := Slice2( img3D, 0,0,pz, 0,sx,1, 1,sy,1 )

ShowImage( img3D )
ShowImage( plane2D )

А следующий пример «вращает» 3D-изображение:

number sx = 6
number sy = 4
number sz = 3

image img3D := RealImage( "Spectrum Image", 4, sx, sy, sz )
img3D = 1000 + icol + irow * 10 + iplane * 100

image rotated := Slice3( img3D, 0,0,0, 0,sx,1, 2,sz,1, 1,sy,1 )

ShowImage( img3D )
ShowImage( rotated  )

С помощью этих команд вы можете получить все виды поворотов, зеркального отображения, биннинга. Если вам нужна полная гибкость для получения любого выражения до 5D из любых исходных данных до 5D, то вам нужна самая универсальная команда SliceN.

Работает точно так же, но нужно указать как размерность исходных данных, так и размерность выходного выражения. Затем необходимо определить «начальную» точку с таким количеством координат, которое предполагает измерение исходных данных, и вам потребуется один триплет спецификации для каждого выходного измерения.

Для исходных данных из N измерений и получения выходных данных из M измерений вам необходимо: 2 + N + 3*M параметров.

В качестве примера давайте извлечем «плоскость» в определенном пространственном положении из данных «4D Diffraction image», которые хранят 2D-изображение в каждом пространственном местоположении 2D-скана:

number sx = 9
number sy = 9
number kx = 9
number ky = 9

image img4D := RealImage( "Diffraction Image", 4, sx, sy, kx, ky )
img4D = 50000 + icol + irow * 10 + idimindex(2)*100 + idimindex(3)*1000

number px = 3
number py = 4

image img2D := SliceN( img4D, 4, 2, px,py,0,0, 2,kx,1, 3,ky,1 )

ShowImage( img4D )
ShowImage( img2D )
person BmyGuest    schedule 04.05.2018
comment
Привет BmyGuest, большое спасибо за эти полезные предложения. Прекрасное изображение пользователя было бы полезно для признания сообществом микроскопистов :) Продолжая эту дискуссию, я хотел бы пойти дальше, чтобы уточнить вопрос. Если есть большой набор 3D-данных, скажем, 256 x 256 x 64, и я хочу извлечь только четные индексированные срезы (срез 0, 2, 4...62). За исключением метода использования SliceN для индивидуального извлечения срезов, а затем объединения их вместе, существует ли какая-либо другая эффективная команда для этой цели? В противном случае весь процесс может быть очень утомительным. - person DM Adventurer; 07.05.2018
comment
@DMAdventurer Просто используйте data3D.slice3( 0,0,0, 0,sx,1, 1,sy,1, 2,sz/2,2 ), где sx,sy,sz - это размер изображения data3D. - person BmyGuest; 07.05.2018
comment
Это действительно хитрый и умный метод. Изменяя начальную точку в направлении z, мы можем выбирать либо четные, либо нечетные проиндексированные срезы, я прав? - person DM Adventurer; 08.05.2018
comment
Кстати, можно ли сэмплировать более конкретный набор слайсов, например, слайс 2, 7, 9, 13... (как-то произвольно)? - person DM Adventurer; 08.05.2018
comment
@DMAdventurer Правильно, и, поместив его в цикл (и суммируя), вы можете выполнить биннинг. Команды «Slice» действительно мощные, поэтому они мне так нравятся. - person BmyGuest; 08.05.2018
comment
@DMAdventurer Нет, неравномерные размеры шагов не поддерживаются в команде Slice. Кстати, если вы считаете, что ответ решает ваш вопрос, было бы хорошо пометить его как принятый. - person BmyGuest; 08.05.2018
comment
Не могли бы вы сказать мне, как отметить его принятым? Я не могу найти эту опцию... (извините, я здесь совсем новичок). - person DM Adventurer; 08.05.2018
comment
@DMAdventurer Конечно: в верхней части каждого ответа/вопроса слева вы видите стрелки «за» и «против», чтобы дать вам оценку поста. Как автор вопроса, вы также найдете маленький значок галочки рядом с ответами, на который вы можете щелкнуть. - person BmyGuest; 08.05.2018