Как многие помнят, я работаю в лаборатории, где мы работаем с живыми и не очень организмами. Науку двигаем, короче. Обычно вперед. Иногда в качестве образцов нам достаются мертвые обезьяны, ткани которых потом идут на экспериментальные задачи. Выглядит обычно это крайне жизнерадостно. Раздается звонок в 11 часов вечера, и тебе сообщают, что в питомнике обезьянка убилась. Почти не поврежденная, соседи только сердце съели. Вздыхаем, лезем в расписание рейсов и едем в аэропорт. На месте тебе выдают нужные запчасти убиенной и складывают в прозрачный контейнер с консервационным раствором. В аэропорт с этим тащиться уже нельзя, так как ограничен провоз жидкостей. Идем на ж/д вокзал на экспресс до Краснодара. Милые девушки на контроле как правило приобретают восхитительный салатовый оттенок при виде медленно кружащихся органов в нежно-розовом растворе.
В-общем, привезли, нарезали все, что нужно ломтиками, покрасили… Но тут оказывается, что полученные исходники нужно обработать и посчитать в автоматическом режиме… Сразу хочу уточнить, что я врач-исследователь, а не профессиональный программист или математик. Поэтому, если что-то покажется ошибочным — буду рад правкам.

Формулируем задачу




Итак, в наличии есть серия срезов окрашенных двумя красителями. Голубоватый — гематоксилин Майера, коричневый — DAB хромаген. На этой иллюстрации пищевод обезьяны, а коричневым окрашены маркеры на панкератин. В принципе, это неважно. Главное, что у нас есть два красителя, которые могут одновременно окрашивать одни и те же структуры. Красить нужно одновременно обоими, иначе непонятно строение среза. Беда в том, что часто для подсчета объектов или определения площади структур с положительной реакцией на антитело нам нужно иметь изображение, где присутствует только один из пигментов. То есть задача может быть сформулирована примерно как "разделить обратно смесь кетчупа с майонезом". И здесь в игру вступает алгоритм цветовой деконволюции.

Цветовая деконволюция


Я постараюсь не влезать в глубокие дебри математики, так как сам с трудом ее понимаю. Цвет пикселя на изображении микропрепарата определяется спектром поглощения света в этой точке. Спектр поглощения соответственно зависит от того, какой пигмент поглощает свет. Однако, у нас неприятная ситуация, когда в одной точке одновременно присутствуют условный синий и коричневый краситель. То есть их спектры накладываются друг на друга.

I — значение интенсивности для данной длины волны. с — концентрация красителя, бета — коэффициент пропорциональности, который зависит от физических свойств данного вещества. То есть, по факту, нам нужно оценить тот вклад который вносит каждый из красителей в красный, зеленый и синий каналы пикселя. Для нашей задачи мы использовали алгоритм A.C. Ruifrok в модификации G. Landini, который написал плагин для открытого ПО ImageJ. ImageJ — софт для пакетной обработки изображения, написанный на Java. Крайне гибкий, позволяет обмазывать его самыми различными плагинами и писать под него скрипты. Сами мы ленивые, пусть за нас машина тонны изображений перемалывает. Но для начала нужно дать ей образцы, относительно которых нужно производить разделение.

Образцы получаем с помощью моноокрашивания срезов. Получаем таким образом RGB цвет опорного эталона. Естественно, что все манипуляции производятся при одинаковой экспозиции и балансе белого. Скармливаем плагину и получаем нужные нам значения:
if (myStain.equals("Custom DAB")){
		// This is the Custom DAB
			MODx[0]=0.66504073;
			MODy[0]=0.61772484;
			MODz[0]=0.41968665;

			MODx[1]=0.4100872;
			MODy[1]=0.5751321;
			MODz[1]=0.70785;

			MODx[2]=0.6241389;
			MODy[2]=0.53632;
			MODz[2]=0.56816506;

Теоретически можно взять готовые предустановленные лабораторные образцы. На практике получается, что в каждой лаборатории красители немного отличаются по оттенку, что делает крайне желательной калибровку на каждой партии. Для того, чтобы этот профиль появлялся в списке вариантов, придется засунуть это в исходный java-файл. Инструкция на странице разработчика. Чем лучше определены векторы красителей, тем ближе комплементарное изображение к белому — то, что остается после выковыривания наших пигментов. Итак, барабанная дробь и результат темной магии:






Еще картинки







Пакетная обработка


Теперь нам нужно, чтобы все это безобразие работало в пакетном варианте. Мы же не хотим тыкать вручную в каждый файл? ImageJ позволяет писать пользовательские скрипты, что удобно для подобных задач. Собственно, создается обычный файл в формате txt, в котором описаны манипуляции с вашим исходником. У меня получилось примерно так:

dir1 = getDirectory("Choose Source Directory ");
dir2 = getDirectory("Choose Destination Directory ");
list = getFileList(dir1);
setBatchMode(true);
for (i=0; i<list.length; i++) {
showProgress(i+1, list.length);
open(dir1+list[i]);
imgName=getTitle(); 
run("Colour Deconvolution", "vectors=[Custom DAB]");
//close windows we don't need 
selectWindow(imgName + "-(Colour_3)"); 
close(); 
selectWindow(imgName +"-(Colour_1)"); 
title = getTitle(); 
saveAs("JPG", dir2 + title);
close(); 
selectWindow(imgName + "-(Colour_2)"); 
title = getTitle(); 
saveAs("JPG", dir2 + title);
close(); 
}


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

UPD. Автор алгоритма приводит достаточно интересные варианты применения — выявление надписей, залитых чернилами другого цвета (Beinecke Rare Book and Manuscript Library, Yale University)

image

image

image

UPD2. Вот эти милые бабуинчики очень любят убивать друг друга нахрен в иерархических стычках.


image

Комментарии (37)


  1. Meklon
    02.09.2015 13:58
    +2

    Жаль нам математику толком не давали. Врачам она обычно нужна в очень усечённом виде.


    1. nikitasius
      04.09.2015 12:12

      Как и чистописание^^


      1. Meklon
        04.09.2015 13:08
        +1

        Я решил эту проблему проще) Стараюсь не писать ничего руками. А почерк кошмарен, да.


  1. Meklon
    02.09.2015 14:14
    +3

    В следующем посте будем помол кофе оценивать автоматическими методами. Из снимков микроскопа) извините, что медленно, но времени немного.


  1. Meklon
    02.09.2015 15:18
    +1

    Разделение гематоксилина и эозина
    image

    image
    image


  1. Cheater
    02.09.2015 16:23
    +4

    Норм, хотя лично мне непривычно видеть манипуляции с изображениями через скрипт, говорящий системе «нажми на этот пункт меню, нажми на окошко, сохрани файл указанный в этом окошке...». Как минимум такой подход требует изучать внутренние скриптовые команды пакета — зачем? Манипуляциями с файлами (сообщать java-приложению пути к файлам, или спрашивать эти пути у юзера) должен заниматься шелл, дело приложения — тупо конвертировать поток символов:

    ls source*.jpg | xargs -I {} java_app -batch «script.java» -infile {} -outfile {}.converted

    Потому что если например захотите передать выход приложения не в файл, а на вход convert (захотелось разрешение уменьшить), или там напрямую распознающему софту, без всяких промежуточных jpg, то весь скрипт придётся переписывать заново.

    Если не секрет, как называется этот брутальный вид мартышек, которые ВЫРЫВАЮТ И ЖРУТ СЕРДЦА УМЕРШИХ СОБРАТЬЕВ? x_x


    1. Meklon
      02.09.2015 16:36
      +3

      Бабуины. Агрессивные твари на редкость. Они вообще крайне склочные. Постоянные стычки иерархические. Еще очень милые слегка плотоядные капуцины могут подобное сотворить.


    1. Meklon
      02.09.2015 16:37
      +2

      Насчет костыльности и неоптимальности соглашусь. Но это из варианта — не стреляйте в пианиста, он играет как умеет. Я не знаю Java)


    1. Moskus
      02.09.2015 23:11
      +1

      С точки зрения программиста, такое решение — абсурд, а с точки зрения пользователя-врача, пользователя-биолога и т.п. — очень даже годное решение, потому что оно позволяет ему не изучать API модулей ImageJ (которых сотни).
      Используемый макроязык позволяет ему достаточно просто формально описать то, что он уже умеет делать, используя GUI.


      1. Meklon
        03.09.2015 13:09
        +1

        Согласен. Жизни не хватит, чтобы одновременно исследованиями заниматься, выучить все языки подряд и еще на баяне играть сбоку. Я сейчас и так зарылся в основы электроники и программирования микроконтроллеров. Тоже та еще тема для непрофессионала. Хотя работает и не взрывается, на удивление.


        1. Alexeyslav
          03.09.2015 17:04
          +1

          Да, кстати на удивление. Ибо я знаю товарища, у которого даже правильно собранные схемы сразу же сгорали со спецэффектами, хотя им взяться в тех схемах просто не от куда, даже переполюсовка не приводит к таким эффектам. И электронные часы у него не приживались категорически — неделю работают потом начинают дико отставать/уходить и вскоре просто перестают работать. Короче дикость какая-то с электроникой происходит с которой он соприкасается. В то же время точно такие же часы у меня работают 20-й год(даже наверно больше)… с точностью +-30 сек в год.


          1. Meklon
            03.09.2015 18:10

            Карма)


        1. Moskus
          04.09.2015 03:38

          Я просто насмотрелся на решения, которые порождают коллективы биологов, когда у них нет ни одного прикрепленного технаря. В худшем смысле этого, напоминает компьютеризацию середины девяностых годов.


          1. Meklon
            04.09.2015 08:21

            У меня все относительно прилично. С owncloud, автоматизацией и разными плюшками. Хотя опыта иногда не хватает в некоторых областях.


            1. Moskus
              04.09.2015 08:39

              Вопрос личной философии. Я вот не люблю программировать и этого не делаю почти, но уважаю автоматизацию во всех ее полезных формах. И знаю кучу инструментов, которые позволяют не программировать или программировать минимально. Потому хорошо представляю, чего можно добиться такими средствами. И когда вижу, что народ собирает данные наблюдений в текстовые файлы в произвольной форме (ну все равно что записывать в блокнот, только перепечатывать не надо) или вручную сортируют что-то, а также рисуют карты в Photoshop, мне удивительно: неужели им не лень и не жаль времени, которое можно потратить на что-то еще? Картинки массово приводят к одному размеру вручную, например… И так далее.


              1. Meklon
                04.09.2015 13:09

                Это мрак, да. Все, что может быть автоматизировано — должно быть автоматизировано.


              1. darthslider
                08.09.2015 10:34

                Друг в кадастровой палате работал, выписки делал. Так как друг знал магию MS Office, а местные девочки нет, то он делал 250 выписок в день, а девочки по 30.


                1. Meklon
                  08.09.2015 13:18

                  Ага. А зарплата одинаковая. Поэтому часто и саботируют все это.


                  1. darthslider
                    08.09.2015 15:49

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


  1. RabbitGP
    02.09.2015 18:00
    +1

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


    1. Meklon
      02.09.2015 18:14
      +1

      Тогда заранее подскажу полезный софт — Cellprofiler. Там вообще полный фарш можно творить с подсчетом клеток, структур, статистики и прочей обработки.


  1. RabbitGP
    02.09.2015 18:36

    Здорово, надеюсь пригодится. С меня подписка, уж очень интересные у Вас статьи и оригинальные.


    1. Meklon
      02.09.2015 19:35

      Рад, что нравится) я вообще странными вещами занимаюсь)


      1. RabbitGP
        02.09.2015 20:10

        Насколько странными?


        1. Meklon
          02.09.2015 20:14
          +4

          Очень) например планирование замкнутого взрыва куска мяса в герметичном сосуде в среде жидкости с последующим исследованием. Применение программы для подсчёта клеток в качестве анализатора полимерных нанокластеров. И вообще я стоматолог.


          1. Maccimo
            02.09.2015 20:22
            +6

            Не зря я всегда опасался стоматологов!


            1. Meklon
              02.09.2015 20:26

              Ох не зря!)


              1. RabbitGP
                02.09.2015 20:34

                Всегда любил стоматологов, особенно обезболивающие и удаление зубов мудрости, это искусство!)))


                1. Meklon
                  02.09.2015 20:52
                  +1

                  Там анатомия тихий мрак с точки зрения точности и работы вслепую. Классическая поклейка обоев через замочную скважину.


          1. withkittens
            02.09.2015 23:00

            замкнутого взрыва куска мяса в герметичном сосуде
            А это зачем, если не секрет?


            1. Meklon
              02.09.2015 23:04
              +1

              Чтобы клетки лопнули от гидравлического удара. Надо)


  1. Alexeyslav
    03.09.2015 17:06

    Очень хорошее и воодушевляющее введение!


    1. Meklon
      03.09.2015 18:10

      Материала тонны… Времени в обрез, увы.


  1. Grisha_Kirilin
    04.09.2015 11:25

    Срезы очень красивые, особенно в негативе. Я, вдохновившись вашими картинками, написал свой алгоритм на Wolfram Mathematica.


    1. Meklon
      04.09.2015 13:12

      О, круть. Я Wolfram иногда использую. С удовольствием почитаю.


  1. sergehog
    04.09.2015 11:56

    Кажется что мат. модель всё-же должна быть другая. У вас фотографии на белом фоне, чем больше красителя — тем сильнее он удаляется от белого. Я бы использовал такую формулу:
    I(x,y) = 1 — a(x,y)A — b(x,y)B, где A и B не синий и коричневый, а их обратные цвета (1-синий), (1-коричневый). А 1 (единица), соответственно белый цвет.
    Впрочем, поскольку задача линейная, всё и так работает.


    1. Meklon
      04.09.2015 13:13

      Сложно сказать. Я нашел рабочий вариант. Не исключаю, что решений множество.