Как стать автором
Обновить
2786.44
RUVDS.com
VDS/VPS-хостинг. Скидка 15% по коду HABR15

Система спектрозональной съемки на Raspberry Pi

Время на прочтение5 мин
Количество просмотров8.2K
Автор оригинала: Elad Orbach
Пояснение переводчика: в статье речь пойдет об изготовлении устройства, которое позволяет делать снимки объекта в различных участках спектра электромагнитных волн.

Цитата из Википедии: спектрозональная съёмка производится для получения изображений деталей объекта, неразличимых в видимом свете.

В статье много фото.
В данном случае автор приводит пример самостоятельного изготовления подобного непростого устройства.

Я уже давно планировал собрать эту систему, и как только у меня появилось свободное время, направился в наш местный хакспейс (TAMI), где этим и занялся. Состоит оно в итоге из нескольких сотен светодиодов, посаженных на одну шину I2C, и темного ящика, который на 1/3 изнутри обклеен алюминиевой фольгой (альтернатива – пенополистирол) для максимально равномерного рассеивания света, а на 2/3 черным картоном для минимизации отражения лучей. Все светодиоды я объединил группами по 4 штуки, чтобы добиться большей яркости.

Начался весь проект с покупки светодиодов, которые обошлись мне около $0.5 каждый.



Затем я красиво разместил их все на алюминиевом листе, который также выступил в роли теплоотвода.



Каждая группа из 4-х светодиодов подключена к МОП-транзистору и мультиплексору (pca9685). Я подумываю заменить этот pca9685 на pca9635 (1кГц против 97кГц) и добавить фототранзистор для настройки ШИМ светодиодов с обратной связью. Также можно проверить время нарастания и спада свечения каждой группы. В качестве источника постоянного тока я задействовал драйвер LDD-700H, а в качестве контроллера Raspberry Pi (код будет приведен далее).



Тестирование светодиодов перед установкой:

Дополнительное тестирование (белый лист А4 и эталон отражения):

Все цвета я проанализировал спектрометром: получилось от ~370нм до ~880нм, а цветовая температура белого 2.7К, 6К, 10К:


Пардон за косячное фото экрана – получил бракованный дисплей для планшета x61t

Далее нужно просверлить большое отверстие в центре алюминиевой пластины под монохроматическую камеру.
Памятка себе: найти фотодиод FDS010?). Для получения реальных значений ШИМ и яркости света фотодиод/фототранзистор должен соответствовать спектру светодиодов. Нашел подходящий в ящике инструментов (FDS10X10?, 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 рублей.
Теги:
Хабы:
+40
Комментарии15

Публикации

Информация

Сайт
ruvds.com
Дата регистрации
Дата основания
Численность
11–30 человек
Местоположение
Россия
Представитель
ruvds