Do it yourself bio-robotics

From Hackers & Designers
Jump to: navigation, search

A reversible modification for a webcam which lets you take pictures of things far less than 1mm wide.

To make the microscope webcam you need the following:

  • Standard webcam with an adjustable focus-lens
  • Computer


Step 1 - Dismantle the webcam cover

Step 2 - Detached the lens of the webcam. Often this optical lens part is partially glued to the front of the webcam but it can be detached by twisting firmly.

Step 3 - Put the lens, up side down, back on the webcam

step 4 - Connect the webcam to the computer

step 5 - To focus, just move the webcam towards or away from the object


Movie bio-robotics

Still from bio-robotics movie

A screenshot of the movie created with the DIY microscope by Jona Andersen, Juriaan Boerman and Mark-Jan Tellingen during the workshop.

The video can be seen here youtu.be/iB5cnaERx9c

Recognizing a plant in a pinch

by James Bryan Graves

When asked to assist how to quickly recognize a plant with a webcam I remembered an Apple WWDC presentation called "Find my iCone" an app that tracked an orange construction pylon using it's color.

I already had some web/Javascript code to do some chromakey (greenscreen) swapping, so I just re-purposed it. However, tracking the correct color of say "purple flowers" needed to be a little less fined grained then #ef0114 (for example, I have no idea what "color" that is by looking at it's hex values), so I grabbed a JS library to print colors as words.

Here's the code:

   <!DOCTYPE html>
   <html>
   <head>
      <script src="ntc.js"></script> 
   </head>
   <body>
     <video id='v'></video>

<h1>I don't see anything.

     <canvas id='c'></canvas>
   <script>
   function rgbToHex(r, g, b) {
       return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
   }
   
   window.addEventListener('DOMContentLoaded', function() {
     var v = document.getElementById('v');
     navigator.getUserMedia = (
       navigator.getUserMedia || 
       navigator.webkitGetUserMedia || 
       navigator.mozGetUserMedia || 
       navigator.msGetUserMedia);
     if (navigator.getUserMedia) {
       // Request access to video only
       navigator.getUserMedia({
         video: true,
         audio: false
       }, function(stream) {
         var url = window.URL || window.webkitURL;
         v.src = url ? url.createObjectURL(stream) : stream;
         v.play();
       }, function(error) {
         alert('Something went wrong. (error code ' + error.code + ')');
         return;
       });
     } else {
       alert('Sorry, the browser you are using doesn\'t support getUserMedia');
       return;
     }
   });
   
   var isStreaming = false,
     v = document.getElementById('v'),
     c = document.getElementById('c'),
     //bg = document.getElementById('bg'),
     grey = document.getElementById('grey');
     con = c.getContext('2d');
     w = 480, 
     h = 480,
     greyscale = false;
   
   v.addEventListener('canplay', function(e) {
     if (!isStreaming) {
       // videoWidth isn't always set correctly in all browsers
       if (v.videoWidth > 0) h = v.videoHeight / (v.videoWidth / w);
       c.setAttribute('width', w);
       c.setAttribute('height', h);
       // Reverse the canvas image
       con.translate(w, 0);
       con.scale(-1, 1);
       isStreaming = true;
     }
   }, false);
   
   v.addEventListener('play', function() {
     // Every 33 milliseconds copy the video image to the canvas
     setInterval(function() {
       if (v.paused || v.ended) return;
       con.fillRect(0, 0, w, h);
       con.drawImage(v, 0, 0, w, h);
       //goingGrey();
       chromaKey();
     }, 33);
   }, false);
   
   var goingGrey = function() {
     var imageData = con.getImageData(0, 0, w, h);
     var data = imageData.data;
     for (var i = 0; i < data.length; i += 4) {
       var bright = 0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2];
       data[i] = bright;
       data[i + 1] = bright;
       data[i + 2] = bright;
     }
     con.putImageData(imageData, 0, 0);
   };
   
   var count = 0;
   var purpleCount = 0;
   var chromaKey = function() {
     var camData = con.getImageData(0, 0, w, h);
     //con.drawImage(bg, 0, 0, w, h);
     var bgData = con.getImageData(0, 0, w, h);
     var imgData = con.createImageData(w, h);
     document.querySelector('h1').innerHTML = 'I see nothing.';
   
     for (i = 0; i < imgData.width * imgData.height * 4; i += 4) {
       var r = camData.data[i + 0];
       var g = camData.data[i + 1];
       var b = camData.data[i + 2];
       var a = camData.data[i + 3];
   
   
       if(++count % 200 == 0) {
         var hexColor = rgbToHex(r,g,b);
   
         var n_match  = ntc.name(hexColor);
         n_rgb        = n_match[0]; // RGB value of closest match
         n_name       = n_match[1]; // Text string: Color name
         n_exactmatch = n_match[2]; // True if exact color match
       
         // compare rgb levels for green and set alphachannel to 0;
         if (n_name.indexOf('Loulou') != -1) {
           console.log(n_name);
           console.log(hexColor);
           if(++purpleCount > 100) {
             document.querySelector('h1').innerHTML = 'I see the plant.';
             imgData.data[i + 0] = 0;
             imgData.data[i + 1] = 0;
             imgData.data[i + 2] = 0;
             imgData.data[i + 3] = 1;    
           }
         } else {
           imgData.data[i + 0] = r;
           imgData.data[i + 1] = g;
           imgData.data[i + 2] = b;
           imgData.data[i + 3] = a;
         }
       }
     }
     con.putImageData(imgData, 0, 0);
   };
   
   </script>
   </body>
   </html>