На али-экспресс продаётся дешевый пластиковый спектроскоп (его обзор), который совсем не плох: через него в солнечном свете видно линии Фраунгофера, и вполне можно рассматривать характерные спектры излучения различных химических элементов в газоразрядных трубках.
Сразу после визуального просмотра спектров хочется иметь возможность сохранения фотографий спектров. Казалось бы, при нынешнем повсеместном распространении камер с этим не должно быть проблем. Однако сопряжение спектроскопа и, например, камеры телефона, затруднительно: из-за специфики картинки спектра автофокусировка и автоэкспозиция дают неудовлетворительные результаты. То есть успешно вести съёмку можно только с использованием достаточно продвинутой фототехники, где предусмотрена возможностью ручной настройки параметров камеры (фокусировки, экспозиции, баланса белого). Плюс остаётся вопрос оптического сопряжения, не тривиальный для не специалиста.
В тоже время известен проект esp32-cam, который позволяет получать видеопоток с дешевых модулей видеокамер (ov2640, ov5640), причём тут у программиста имеется исчерпывающий контроль над режимами работы камеры.
К тому же модули видеокамер достаточно малогабаритные, их можно легко засунуть прямо в спектроскоп. Для этого достаточно снять с спектроскопа защитное стекло, и вставить вместо него непрозрачную шайбу такого же диаметра. В центре шайбы проделывается круглое отверстие, в которое просунут модуль камеры. Сзади приклеена дополнительная шайба с квадратным отверсием по размерам камеры: она мешает камере свободно поворачиваться. Проще использовать модуль камеры с достаточно длинным шлейфом, чтобы была большая свобода в размещении основной платы с контроллером esp32, но в принципе даже это не обязательно.
Конечно, такое оптическое сопряжение далеко от идеала! Из общего растра 1600x1200 пикселей (для камеры ov2640) спектр занимает порядка 520x200 пикселей, т.е. полезно используется едва ли треть от длины матрицы. Это для датчика с заявленным полем зрения 66°, т.е. оптимальным был бы выбор объектива с полем зрения ~22°, что потенциально могло бы увеличит спектральное разрешение втрое. Но как можно просто, изящно и дешево решить эту проблему - я не знаю.
Утешение одно - благодаря полному программному контролю над камерой можно выбрать регион интереса и передавать по интерфейсу для дальнейшего анализа только полезные данные.
На практике помимо установки региона интереса у камеры функцией set_res_raw() в IDF-IDE необходимо выполнить ещё ряд настроек. Очень важно отключить функции коррекции сбойных пикселей вызовами set_wpc(false) и set_bpc(false), так как изображения спектров очень специфические и алгоритм выявления сбойных пикселей даёт на них сбои. Возможно стоит выключить гамма-коррекцию вызовом set_raw_gma(true), так как польза от неё довольно неоднозначная. Управлять времени экспозиции и усилением вероятно лучше вручную, вызвав set_exposure_ctrl(false) и set_gain_ctrl(false) и меняя времени экспозиции и усиление вызовами set_aec_value и set_agc_gain.
Вообще качество камер проекта esp32-cam отвратительное: у них низкая чувствительность и большие шумы даже по сравнению с бюджетными телефонам. Но при съёмке спектров данные недостатки могут быть частично скомпенсированы усреднением большого количества полученных кадров (как в астрономии). Расширить динамический диапазон можно путем съёмки нескольких серий кадров: сперва на минимальном усилении (и даже при сниженном времени экспозиции), чтобы были видны только самые сильные линии, с дальнейшим постепенным повышением усиления (чтобы можно было увидеть слабые линии).
Что касается формата выдачи данных, то конечно сырые измерения были бы лучше всего. Соответствующий информационный поток велик, но его можно снижать, уменьшая высоту фрагмента интереса. Однако для камер ov2640 доступен только формат rgb565 с малой битностью (и мне вообще не удалось добиться выдачи сырых данных на практике). Выдача jpeg хороша для получения обзорных изображений (для определения того, какой фрагмент несёт полезную информацию), ну и для фрагментов подходит (изображения спектров должны сжиматься хорошо).
Качество jpeg-сжатия лучше выбирать повыше (с меньшим аргументом функции set_quality), однако у меня по мере увеличения объёма jpeg появляются странные сбои, поэтому реализована адаптация: если размер кадра больше 52 кб, то качество jpeg снижается, а если ниже 37 кб то повышается. Следует отметить, что сжатие в jpeg понижает вдвое пространственное разрешение для цветовых компонент, что плохо, хотя и соответствует реалиям визуального восприятия (см. далее). Вообще размеры фрагмента интереса даже при использовании jpeg следует максимально уменьшать, чтобы сжатие в jpeg вносило меньше искажений.
Для уменьшения помех я не использовал Wi-fi для связи с камерой esp32, вместо этого видеопоток передавался через com-интерфейс на скорости 5 мбит/сек.
Вероятно для спектроскопа автоматический баланс белого у камеры следует отключать (вряд ли он способен работать правильно). Для ov2640 достаточно вызвать set_whitebal(false).
Вообще говоря, при съёмке спектра передача цвета не нужна. Но поскольку используется цветная матрица (а только такие сенсоры проекта esp32-cam обладают хорошим разрешением), то напрашивается следующий подход: брать сигнал с тех элементов, где он максимален (а значит где лучше отношение сигнал/шум). Например, сперва синяя часть спектра фиксируется синими фотоэлементами, затем средняя часть - зелеными, затем красными. При этом передачу цвета по интерфейсу желательно отключать, потому что jpeg имеет меньшее разрешение для цветоразностных компонент.
К сожалению, реализация данного подхода для сенсора ov2640 далеко не тривиальна. Во-первых, документация на датчик не подразумевает возможности выделения отдельных каналов. Хотя в api камеры реализована функция set_wb_mode() ручного задания различных фиксированных вариантов баланса белого. Анализ исходников показывает, что работа set_wb_mode() в ручном режиме использует недокументированные регистры 0xcc, 0xcd, 0xce, в которых хранятся коэффициенты цифрового усиления для каналов R,G,B (для их использования должна быть включена возможность ручной регулировки усиления вызовом set_awb_gain(true) и установлен бит 6 в недокументированном регистре 0xc7 вызовом set_wb_mode() с ненулевым параметром). Во-вторых, выделение отдельного канала (установкой для других нулевого усиления) работает не идеально, например, при повышении общего усиления вызовом set_agc_gain яркость в выделенном канале R или B может начать падать вместо роста, возможно из-за зашкала АЦП на ярком зеленом. В-третьих, после выделения отдельного канала затруднительно сформировать соответствующее полутоновое изображение: у ov2640 отсутствует возможность произвольного задания матрицы преобразования из RGB в YUV. Можно обнулить цветовые компоненты UV вызовом set_special_effect(), но тогда яркость для чистых цветов сильно падает (стандартные коэффициенты для rgb это 0.299, 0.587, 0.114), а компенсация этого снижения путем увеличения контраста не эффективна, потому что сперва происходит квантование, а потом уже контрастирование. В итоге для синего канала точность представления яркости падает в 8 раз (впрочем, у призмы синий диапазон растянут и снижение пространственного разрешения за-за jpeg не так существенно).
На практике установлено, что для камеры ov2640 выделение отдельных каналов не целесообразно. Наоборот, наблюдалось, что пространственное разрешение в выделенном красном канале оказывалось ниже, чем в зеленом. Возможно это какая-то внутренняя фильтрация... Но вообще, в зеленом канале вдвое больше пикселей, а действие фильтров не настолько уж и выраженное. Поэтому пожалуй лучшая стратегия для ov2640 это вызвать set_awb_gain(false). И лишь иногда при включении монохромного режима можно наблюдать незначительное улучшение разрешения.
Ниже показан полученный камерой esp32-cam спектр излучения тлеющего разряда в гелии. При съёмке использовался датчик ov2640 с заявленным полем зрения 66°, вариант без IR-фильтра (чтобы оценить, что есть интересного в ближнем ИК-диапазоне). Изображение получено при трех вариантах усиления esp32-cam.
Характерные спектральные линии гелия просматриваются хорошо, вот эталон. Наблюдаемая ширина линий сильно зависит от выбранного усиления, что не удивительно: яркости линий в спектре очень сильно различаются. Но похоже, что хитрой математической обработкой с выходом на субпиксельное разрешение повысить реальное разрешение не удастся.
Спектроскоп видит на границе УФ линию гелия 388.86 нм, однако линия ртути 365 нм уже не видна, для матрицы ov2640 заявленная верхняя граница ~380 нм.
В ближнем ИК на границе чувствительности матрицы видна мощная инфракрасная линия гелия 1083 нм. Это точно не артефакт: в спектре зеленого лазера 532 нм спектроскоп видит известные побочные линии 808 и 1064 нм.
Шкала длин волн для призменного спектроскопа сильно нелинейная. На рисунке ниже показана полученная по спектру гелия оценка зависимости номера пикселя изображения от длины волны (красные маркеры - данные прямых измерений по изображению, апроксимация на основе формулы Коши pix(λ) = p0 + p1/λ2 + p2/λ4 + ...).
Для 388 нм разрешение 0.17 нм/пиксель, на 580нм пиксель уже 1.17 нм/пиксель, на 750 нм уже 3 нм/пиксель, на 1083 нм целых 14 нм/пиксель. Т.е. в области ИК разрешение падает катастрофически, так что польза от отсутствия ИК-фильтра неоднозначная (к тому же мощное ИК излучение может затмевать видимую часть спектра).
Таким образом, использовать esp32-cam для съёмки спектров можно, особенно если не нужно высокое спектральное разрешение. Но конечно разрешение камеры ov2640 не достаточное по сравнению с визуальным наблюдением и качественной фототехникой. Возможно, немного повысить параметры можно используя более качественный сенсор ov5640 (матрица 2592x1944 против 1600x1200 у ov2640, это 1.6 раза), но ov5640 сильно греется и при его размещении прямо в спектроскопе необходимо предусматривать теплоотвод. Полноценное оптическое сопряжение выглядит перспективнее, с ним разрешение можно повысить втрое, но это уже куда сложнее и дороже.
Можно посмотреть ещё съёмки спектров на данный спектроскоп + esp32-cam.
Ваши комментарии можно добавить тут.