Difference between revisions of "Do it yourself bio-robotics"

From Hackers and Designers
Jump to navigation Jump to search
(Created page with "Insert DIY steps making microscope webcam Category:WriteMe Category:Print Category:Web")
 
 
(31 intermediate revisions by 3 users not shown)
Line 1: Line 1:
Insert DIY steps making microscope webcam
A reversible modification for a webcam which lets you take pictures of things far less than 1mm wide.


[[Category:WriteMe]]
To make the microscope webcam you need the following:
[[Category:Print]]
* Standard webcam with an adjustable focus-lens
[[Category:Web]]
* 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'''
 
[[File:Screen-Shot-2015-10-22-2.png|600px|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 [https://youtu.be/iB5cnaERx9c 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 [http://chir.ag/projects/ntc/ 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>
      &lt;h1>I don't see anything.</h1>
      <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>

Latest revision as of 12:51, 16 December 2015

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>