[Перевод] Система спектрозональной съемки на Raspberry Pi
Пояснение переводчика: в статье речь пойдет об изготовлении устройства, которое позволяет делать снимки объекта в различных участках спектра электромагнитных волн.Цитата из Википедии: спектрозональная съёмка производится для получения изображений деталей объекта, неразличимых в видимом свете.
В статье много фото.
В данном случае автор приводит пример самостоятельного изготовления подобного непростого устройства.
Я уже давно планировал собрать эту систему, и как только у меня появилось свободное время, направился в наш местный хакспейс (TAMI), где этим и занялся. Состоит оно в итоге из нескольких сотен светодиодов, посаженных на одну шину I2C, и темного ящика, который на ⅓ изнутри обклеен алюминиевой фольгой (альтернатива — пенополистирол) для максимально равномерного рассеивания света, а на 2/3 черным картоном для минимизации отражения лучей. Все светодиоды я объединил группами по 4 штуки, чтобы добиться большей яркости.
Начался весь проект с покупки светодиодов, которые обошлись мне около $0.5 каждый.
Затем я красиво разместил их все на алюминиевом листе, который также выступил в роли теплоотвода.
Каждая группа из 4-х светодиодов подключена к МОП-транзистору и мультиплексору (pca9685). Я подумываю заменить этот pca9685 на pca9635 (1кГц против 97кГц) и добавить фототранзистор для настройки ШИМ светодиодов с обратной связью. Также можно проверить время нарастания и спада свечения каждой группы. В качестве источника постоянного тока я задействовал драйвер LDD-700H, а в качестве контроллера Raspberry Pi (код будет приведен далее).
Тестирование светодиодов перед установкой:
Дополнительное тестирование (белый лист А4 и эталон отражения): Все цвета я проанализировал спектрометром: получилось от ~370нм до ~880нм, а цветовая температура белого 2.7К, 6К, 10К:
Пардон за косячное фото экрана — получил бракованный дисплей для планшета x61t
Далее нужно просверлить большое отверстие в центре алюминиевой пластины под монохроматическую камеру.
Памятка себе: найти фотодиод FDS010?). Для получения реальных значений ШИМ и яркости света фотодиод/фототранзистор должен соответствовать спектру светодиодов. Нашел подходящий в ящике инструментов (FDS10×10?, S2387–1010R?, 340нм-110нм ?).
Думаю, пока этого будет достаточно. Похоже, что стандартным решением для преобразования тока фотодиода в напряжение является LTC1050.
Съемка экрана планшета (лист авокадо) на телефон. Изображение получено с монохроматической камеры, еще не откалиброванной и не синхронизированной со светодиодами.
Апдейт по сборке: добавил сенсорный дисплей — нужно еще исправить драйвер eGalax (apt install xserver-xorg-input-evdev
, отредактировать /etc/X11/xorg.conf, заменить libinput на evdev, apt install xinput-calibrator
, поменять местами оси x-y дисплея).
Все запитано от одного БП (драйвер светодиодов 15В, дисплей 12В, Pi 5В).
Просверлил отверстие
Тест системы с временным держателем камеры
Притащил из TAMI несколько кусков анодированного алюминия, из которых собрал настраиваемый кронштейн для камеры.
Дополнительные фото
Апдейт: важно, чтобы в объектив попадал только отраженный от тестируемого объекта свет, поэтому я измерил отверстие и подобрал подходящую ПВХ-трубу, которая вошла в него достаточно плотно. Обрезал я ее коротковато — по факту оказалось, что лучше ее сделать длиннее.
Измерение отверстия
Измерение ПВХ-трубы
Установил объектив с более широким углом обзора
Похоже, что мне удалось добиться улучшения, несмотря на слишком короткую трубу (думаю, желательна длина от 10 см). В качестве временного решения я ее наращу с помощью черного картона и оберну внешнюю сторону фольгой.
Покрасил в черный. После высыхания снаружи оберну фольгой
Ниже очередное видео, теперь с листом винограда. Яркость светодиодов еще не откалибрована, и некоторые диапазоны лист поглощает. Плюс не помогло практически полное закрытие затвора объектива. Попробую снять другое видео завтра.
Изображение получилось «в кружке» из-за того, что я излишне нарастил трубу (20 см), в результате чего угол обзора захватывает ее край. В дальнейшем я планирую сделать трубу уже с настраиваемой длинной под разные объективы.
Обновленный вид установки
Добавил магнитный фиксатор дверцы
Еще одно видео. Здесь потеряна пара кадров из-за недостатка питания для Pi. На этот раз снимал лист картофеля с обработкой изображения при помощи OpenCV (функция CLAHE).
Находясь в ожидании заказанного апгрейда в виде Nvidia Jetson, решил поработать над косметикой.
Дополнительные фото
И вот мой «презент» готов к ведению многозональной съемки.
Как и обещал, привожу:
Кодfrom __future__ import division import time import Adafruit_PCA9685 import cv2 from pyueye import ueye import ctypes import datetime pwm = Adafruit_PCA9685.PCA9685(address = 0x40) #1st pwm1 = Adafruit_PCA9685.PCA9685(address = 0x41) #2nd pwm2 = Adafruit_PCA9685.PCA9685(address = 0x42) #3rd pwm.set_pwm_freq(1000) pwm1.set_pwm_freq(1000) pwm2.set_pwm_freq(1000) spec = "avo_leaf" #name of speciment led = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31] lux = [1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931] #temporary initial value 0, 4095 for x,y in zip(led, lux): if (x < 16): pwm.set_pwm(x,y,0) #led on 1st mux elif ( x>14 and x<32): pwm1.set_pwm(x-16,y,0) #led on 2nd mux elif (x>31 and x<33): pwm2.set_pwm(x-32,y,0) #led on 3rd mux else: print(x) hcam = ueye.HIDS(1) pccmem = ueye.c_mem_p() memID = ueye.c_int() hWnd = ctypes.c_voidp() ueye.is_InitCamera(hcam, hWnd) sensorinfo = ueye.SENSORINFO() ueye.is_GetSensorInfo(hcam, sensorinfo) ueye.is_AllocImageMem(hcam, sensorinfo.nMaxWidth, sensorinfo.nMaxHeight,24, pccmem, memID) ueye.is_SetImageMem(hcam, pccmem, memID) nret = ueye.is_FreezeVideo(hcam, ueye.IS_WAIT) if (nret == 0): print("camera") else: print("____problem!!!____") FileParams = ueye.IMAGE_FILE_PARAMS() FileParams.pwchFileName = spec + "_led_"+str(x+1)+"_cam_"+ datetime.datetime.now().strftime("%s") + ".bmp" FileParams.nFileType = ueye.IS_IMG_BMP FileParams.ppcImageMem = None FileParams.pnImageID = None nret = ueye.is_ImageFile(hcam, ueye.IS_IMAGE_FILE_CMD_SAVE, FileParams, ueye.sizeof(FileParams)) if (nret == 0): print("camera") else: print("____problem!!!____") ueye.is_FreeImageMem(hcam, pccmem, memID) ueye.is_ExitCamera(hcam) if (x < 16): pwm.set_pwm(x,0,0) #led off 1st mux elif ( x>14 and x<32): pwm1.set_pwm(x-16,0,0) #led off 2nd mux elif (x>31 and x<33): pwm2.set_pwm(x-32,0,0) #led off 3rd mux else: print(x)
Заключение
В целом получился занятный проект, и я планирую довести его до ревизии 2.0. В частности:
- заменить Raspberry Pi (~35$) на Nvidia Jetson Nano (~99$);
- возможно, использовать машинное обучение для улучшения контраста;
- пересобрать нижнюю часть для лучшего поглощения света;
- достать несколько многоцветных лазеров;
- использовать оптоволокно для подсветки в углах;
- сделать установку портативной (уменьшить, реализовать возможность складывания и добавить аккумулятор).
В качестве дополнения рекомендую ознакомиться с реализацией продвинутого аналога подобной системы специалистами NASA. Вот их небольшое видео:
Конкурс статей от RUVDS.COM. Три денежные номинации. Главный приз — 100 000 рублей.