DIY Spectrometer



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.

Powered by Blogger.