DIY Spectrometer
Tuesday, May 14, 2013
Some time ago I had some time, a spare webcam, Matlab and some Legos lying around, so I began building a Spectrometer from it. Now, to the hardware, you just need a dark box, with no light infusing in it, and a piece of dvd to use as diffraction grid. This website will help to answer most questions: http://publiclaboratory.org/tool/spectrometer
At the time, their software didn't ran on my computer so I started prototyping my own in matlab. The code is below:
% Copyright 2014 Érico Porto % Licensed under the Apache License, Version 2.0 (the "License"); % you may not use this file except in compliance with the License. % You may obtain a copy of the License at % http://www.apache.org/licenses/LICENSE-2.0 % Unless required by applicable law or agreed to in writing, software % distributed under the License is distributed on an "AS IS" BASIS, % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % See the License for the specific language governing permissions and % limitations under the License. vid = videoinput('winvideo', 1, 'YUY2_640x480'); preview(vid); pause(4); color_spectrum = ycbcr2rgb(getsnapshot(vid)); %correct the orientation binImg = im2bw(color_spectrum,0.24); I = bwlabel(binImg); a= regionprops(I,'MajorAxisLength','Area','Orientation'); [areaMaxArea, indexMaxArea]= max([a(:).Area]); angle = a(indexMaxArea).Orientation; color_spectrum = imrotate(color_spectrum,-angle,'bilinear','crop'); %now I want to get the main rectangle binImg = im2bw(color_spectrum,0.08); I = bwlabel(binImg); a= regionprops(I,'BoundingBox','Area'); [areaMaxArea, iMA]= max([a(:).Area]); subImage = imcrop(color_spectrum,round(a(iMA).BoundingBox)); %here I'm guessing the light wavelength! %I think I need to use 380nm and 750nm as my bounding XAxis=zeros(size(subImage,2),1); XAxis(1)=380.0; XAxis(length(XAxis))=750.0; %find blue - 472nm [intensity, blueI] = max(mean(subImage(:,:,3))); XAxis(blueI)=472.0; %find green - 532nm [intensity, greenI] = max(mean(subImage(:,:,2))); XAxis(greenI)=532.0; %find red - 685nm [intensity, redI] = max(mean(subImage(:,:,1))); XAxis(redI)=685.0; %Now I will run and fill the zeros... beginI=1; endI=blueI; for i = (beginI+1):(endI-1) XAxis(i)= XAxis(beginI) + ((XAxis(endI)-XAxis(beginI))/(endI-beginI)) * (i-beginI); end beginI=blueI; endI=greenI; for i = (beginI+1):(endI-1) XAxis(i)= XAxis(beginI) + ((XAxis(endI)-XAxis(beginI))/(endI-beginI)) * (i-beginI); end beginI=greenI; endI=redI; for i = (beginI+1):(endI-1) XAxis(i)= XAxis(beginI) + ((XAxis(endI)-XAxis(beginI))/(endI-beginI)) * (i-beginI); end beginI=redI; endI=length(XAxis); for i = (beginI+1):(endI-1) XAxis(i)= XAxis(beginI) + ((XAxis(endI)-XAxis(beginI))/(endI-beginI)) * (i-beginI); end %this ends, the wavelength vector is ready for use! figure(2); colormap(gray(256)); gray_spectrum=((double(subImage(:,:,1))+double(subImage(:,:,2))+double(subImage(:,:,3)))/3.0); image(gray_spectrum); figure(3); colormap(gray(256)); Grayimg_reversed=flipud(gray_spectrum); graph=mean( Grayimg_reversed ,1); %Finally I can plot a nice graph with meaningfull axis plot(XAxis,graph); pause(3); delete(vid);
For improvement, I would suggest being able to save the resulting vector with easy to some sort of table, to later use this big table to guess what I have in front of it - using Hungarian or other solver method.