Как стать автором
Обновить

Комментарии 51

Жаль нам математику толком не давали. Врачам она обычно нужна в очень усечённом виде.
Как и чистописание^^
Я решил эту проблему проще) Стараюсь не писать ничего руками. А почерк кошмарен, да.
Да тут система линейный уравнений, которую мы даже в школе решали, просто записанная в форме линейной алгебры. Для вашей задачи это:

0.66504073 * x + 0.61772484 * y + 0.41968665 * z = R
0.4100872  * x + 0.5751321  * y + 0.70785    * z = G
0.6241389  * x + 0.53632    * y + 0.56816506 * z = B

Где R, G, B — значения цвета пикселя (конкретные числа), а x, y, z — концентрация трех красителей.
Имеем систему из трех линейных уравнений с тремя неизвестными.

(Правда, в статье не RGB, а логарифм RGB, но это все равно конкретные числа)
Хм, спасибо)
В следующем посте будем помол кофе оценивать автоматическими методами. Из снимков микроскопа) извините, что медленно, но времени немного.
Разделение гематоксилина и эозина
image

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

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

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

Если не секрет, как называется этот брутальный вид мартышек, которые ВЫРЫВАЮТ И ЖРУТ СЕРДЦА УМЕРШИХ СОБРАТЬЕВ? x_x
Бабуины. Агрессивные твари на редкость. Они вообще крайне склочные. Постоянные стычки иерархические. Еще очень милые слегка плотоядные капуцины могут подобное сотворить.
Насчет костыльности и неоптимальности соглашусь. Но это из варианта — не стреляйте в пианиста, он играет как умеет. Я не знаю Java)
С точки зрения программиста, такое решение — абсурд, а с точки зрения пользователя-врача, пользователя-биолога и т.п. — очень даже годное решение, потому что оно позволяет ему не изучать API модулей ImageJ (которых сотни).
Используемый макроязык позволяет ему достаточно просто формально описать то, что он уже умеет делать, используя GUI.
Согласен. Жизни не хватит, чтобы одновременно исследованиями заниматься, выучить все языки подряд и еще на баяне играть сбоку. Я сейчас и так зарылся в основы электроники и программирования микроконтроллеров. Тоже та еще тема для непрофессионала. Хотя работает и не взрывается, на удивление.
Да, кстати на удивление. Ибо я знаю товарища, у которого даже правильно собранные схемы сразу же сгорали со спецэффектами, хотя им взяться в тех схемах просто не от куда, даже переполюсовка не приводит к таким эффектам. И электронные часы у него не приживались категорически — неделю работают потом начинают дико отставать/уходить и вскоре просто перестают работать. Короче дикость какая-то с электроникой происходит с которой он соприкасается. В то же время точно такие же часы у меня работают 20-й год(даже наверно больше)… с точностью +-30 сек в год.
Карма)
Я просто насмотрелся на решения, которые порождают коллективы биологов, когда у них нет ни одного прикрепленного технаря. В худшем смысле этого, напоминает компьютеризацию середины девяностых годов.
У меня все относительно прилично. С owncloud, автоматизацией и разными плюшками. Хотя опыта иногда не хватает в некоторых областях.
Вопрос личной философии. Я вот не люблю программировать и этого не делаю почти, но уважаю автоматизацию во всех ее полезных формах. И знаю кучу инструментов, которые позволяют не программировать или программировать минимально. Потому хорошо представляю, чего можно добиться такими средствами. И когда вижу, что народ собирает данные наблюдений в текстовые файлы в произвольной форме (ну все равно что записывать в блокнот, только перепечатывать не надо) или вручную сортируют что-то, а также рисуют карты в Photoshop, мне удивительно: неужели им не лень и не жаль времени, которое можно потратить на что-то еще? Картинки массово приводят к одному размеру вручную, например… И так далее.
Это мрак, да. Все, что может быть автоматизировано — должно быть автоматизировано.
Друг в кадастровой палате работал, выписки делал. Так как друг знал магию MS Office, а местные девочки нет, то он делал 250 выписок в день, а девочки по 30.
Ага. А зарплата одинаковая. Поэтому часто и саботируют все это.
Хуже того, в подобных коллективов особо умных сотрудников обычно всячески выживают, т.к. на их фоне все остальные смотрятся не очень. А друг взвыл, уволился через пару месяцев и уже давно зарабатывает игрой в покер не выходя из дома.
Как интересно и даже непривычно, такой подход очень неординарный, хотя прогресс, скоро всё будет выдаваться в скриптах. Вообще статья понравилась, очень познавательная. Пока учусь на биолога, но думаю скоро придётся так же работать с пигментацией растений.
Спасибо за статью
Тогда заранее подскажу полезный софт — Cellprofiler. Там вообще полный фарш можно творить с подсчетом клеток, структур, статистики и прочей обработки.
Здорово, надеюсь пригодится. С меня подписка, уж очень интересные у Вас статьи и оригинальные.
Рад, что нравится) я вообще странными вещами занимаюсь)
Насколько странными?
Очень) например планирование замкнутого взрыва куска мяса в герметичном сосуде в среде жидкости с последующим исследованием. Применение программы для подсчёта клеток в качестве анализатора полимерных нанокластеров. И вообще я стоматолог.
Не зря я всегда опасался стоматологов!
Ох не зря!)
Всегда любил стоматологов, особенно обезболивающие и удаление зубов мудрости, это искусство!)))
Там анатомия тихий мрак с точки зрения точности и работы вслепую. Классическая поклейка обоев через замочную скважину.
замкнутого взрыва куска мяса в герметичном сосуде
А это зачем, если не секрет?
Чтобы клетки лопнули от гидравлического удара. Надо)
Очень хорошее и воодушевляющее введение!
Материала тонны… Времени в обрез, увы.
О, круть. Я Wolfram иногда использую. С удовольствием почитаю.
Кажется что мат. модель всё-же должна быть другая. У вас фотографии на белом фоне, чем больше красителя — тем сильнее он удаляется от белого. Я бы использовал такую формулу:
I(x,y) = 1 — a(x,y)A — b(x,y)B, где A и B не синий и коричневый, а их обратные цвета (1-синий), (1-коричневый). А 1 (единица), соответственно белый цвет.
Впрочем, поскольку задача линейная, всё и так работает.

Сложно сказать. Я нашел рабочий вариант. Не исключаю, что решений множество.
Спасибо за интересную наводку! Я нашел оригинальную статью («Quantification of histochemical staining by color deconvolution» A. Ruifrok, A.Johnston) и обнаружил несколько важных моментов:

  1. Исходное изображение должно содержать линейные интенсивности R, G и B составляющих. Обычно изображение в современных цифровых камерах проходит постобработку, как минимум — гаммирование (возведение в степень). Причем в общем случае нереально понять, в какую степень была возведена интенсивность пикселя. Конкретно в статье авторы специально выставили гамму в единицу в своих фотоаппаратах. Кроме того, яркости окрашенных пикселей не должны быть пересвечены.
  2. Формула интенсивности яркости пикселя для одного красителя определяется по нелинейному закону Бугера-Ламберта-Бера: Iₓ = I₀ₓ · exp(-A · cₓ), где I₀ₓ — интенсивность света на входе, Iₓ — интенсивность света на выходе, А — концентрация красителя, cₓ — коэффициент поглощения красителя, а маленькая «х» означает конкретный канал цвета (R, G, B). Таким образом, для получения линейной формулы яркости пикселей относительно концентрации красителя необходимо взять логарифм каждого пикселя.
  3. Цвета красителей известны. Каждый пиксель обрабатывается отдельно и независимо от других. По интенсивности каждого канала log(RGB) пикселя находится линейная комбинация концентрации красителей. Никакой особенной магии, простейшая задача линейной алгебры.
* гаммирование => гамма-коррекция
Посмотри мой софт, который я с тех пор написал. Вдруг пригодится. Документация максимально подробная.
github.com/meklon/morphostain
Спасибо, глянул и просмотрел код. Исходное изображение и базисные цвета не подвергаются логарифмированию перед цветовой деконволюцией — а это не соответствует модели формирования интенсивности пикселя в статье. Почему?
Дело в том, что без логарифмирования ваша программа будет работать только в узком диапазоне концентрации красителей. Наверное, не надо будет тогда и порог яркости пикселя выставлять — в логарифмическом пространстве разница между темным и светлым пикселем сократится и алгоритм заработает для самых темных/светлых участков.
Спасибо, я подумаю. В принципе, в текущем варианте она уже нормально работает. Пороги все равно нужны. Только исследователь может сказать какие участки положительно окрашены, а какие нет.
Имея базис линейно-независимых векторов, не мудрено разложить любой вектор по этому базису — и это будет «работать». Только что будет в ответе — концентрация или «е» в степени концентрация, или некие коэффициенты, которые коррелируют с концентрацией?
Спасибо, только смотрите, чтобы не получилось как с Готлобом Фреге, когда он получил от Рассела опровержение работы всей его жизни незадолго до публикации второго тома своих «Основ» =) (Фреге добавил такой эпилог в свою книгу: «Вряд ли ученый может встретиться с чем-то более нежеланным, чем разрушение самой основы своей работы сразу после ее завершения»)
Здесь не получится) Смысл в том, что это автоматизация ручного варианта. Исследователь глазами проверяет корректность положительных областей. Без софта — это микроскоп и палетки с клеточками. Насчет переосмысления алгоритма обязательно подумаю. Тем более, что это только пара функций и дефолтные коэффициенты. Остальная логика изолирована и не пострадает.
Кстати, я посмотрел оригинальный плагин — автор логарифмирует цветовое пространство согласно статье:

// log transform the RGB data
int R = (pixels[j] & 0xff0000)>>16;
int G = (pixels[j] & 0x00ff00)>>8 ;
int B = (pixels[j] & 0x0000ff);
double Rlog = -((255.0*Math.log(((double)R+1)/255.0))/log255);
double Glog = -((255.0*Math.log(((double)G+1)/255.0))/log255);
double Blog = -((255.0*Math.log(((double)B+1)/255.0))/log255);
Да, надо переделать, спасибо.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории