TensorFlow.js භාවිතා කර වස්තු හඳුනාගන්නා ස්මාර්ට් කැමරාවක් සාදන්නේ කෙසේ ද?

Submitted by kamal on
TensorFlow.js object detection camera

TensorFlow.js කියන්නේ යාන්ත්‍රික ඉගෙනුම් මොඩල (Machine Learning Models) පුහුණු කිරීමට සහ භාවිතයට ගැනීමට හැකි පරිදි සාදා ඇති JavaScript පුස්තකාලයක් (library). මෙම ලිපියෙන් විස්තර කෙරෙන්නේ එය භාවිතා කොට වස්තු හඳුනාගන්නා වෙබ් බ්‍රවුසරයක් ඇසුරේ ක්‍රියාත්මක වන ස්මාර්ට් කැමරාවක් (object detection camera) සකසා ගන්නා ආකාරයයි. මෙම ලිපිය ගූගල් ආයතනයේ Jason Mayes විසින් රචිත ලිපි පෙළක් සහ මෘදුකාංග ඇසුරෙනුයි ලියා තිබෙන්නේ. ඉංග්‍රීසියෙන් එම මුල් ලිපි පෙළ කියවීමට කැමති අයට "මෙතැනින්" ඒ වෙත යොමුවෙන්න පුළුවන්.

ආදර්ශකය (Demo)

ආදර්ශකයට සබැඳිය: https://demo.training.lk/artificial-intelligence/tensorflow.js/01-smartcam/

zip ගොනුවක් ලෙස බාගත කරන්න: 01-smartcam.zip (~ 5kB)

ක්‍රියාකාරිත්වය

ඉහත zip ගොනුවේ අන්තර්ගතය ෆෝල්ඩරයකට unzip කරන්න. අන්තර්ගත ගොනු මේ ආකාරයේ වනු ඇති:

01-smartcam/
├── index.html
├── script.js
└── style.css

එහි  index.html ගොනුව Text editor මෘදුකාංගයක විවෘත කොට බැලුවොත් එහි පහත දැක්වෙන ආකාරයේ කේත කොටසක් දකින්න පුළුවන්:

    <section id="demos" class="invisible">
     <p>...</p>
     
     <div id="liveView" class="camView">
       <button id="webcamButton">වෙබ් කැමරාව සක්‍රීය කරන්න</button>
       <video id="webcam" autoplay muted width="640" height="480"></video>
     </div>
   </section>

එහි ක්ලික් කිරීමට හැකි බොත්තමක් සහ වීඩියෝ ප්‍රවාහයක් (video stream) වෙබ් පිටුවේ දැක්වීමට උවමනා කරන කේත අඩංගුයි.

තවද එම ගොනුවේ අවසානයට ආසන්නව මෙම කේත කොටස දකින්න පුළුවන්:

    <!-- Import TensorFlow.js library -->
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs/dist/tf.min.js" type="text/javascript"></script>
    <!-- Load the coco-ssd model to use to recognize things in images -->
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd"></script>
    
    <!-- Import the page's JavaScript to do some stuff -->
    <script src="script.js"></script>

එහි පළමු script ටැග් එකෙන් කෙරෙනුයේ TensorFlow.js ලයිබ්‍රරිය ලෝඩ් කිරීමයි. එහි දෙවන script ටැග් එකෙන් කෙරෙනුයේ වස්තු හඳුනාගත හැකි යාන්ත්‍රික ඉගෙනුම් මොඩලයක් වන COCO-SSD මොඩලය ලෝඩ් කිරීමට අවශ්‍ය ආවරක කේතය (wrapper code) ලෝඩ් කිරීමයි. තෙවන script ටැග් එකෙන් කෙරෙනුයේ index.html පිටුවේ විශේෂිතව භාවිතා වන JavaScript කේත අඩංගු script.js ගොනුව ලෝඩ් කිරීමයි.

script.js ගොනුවේ ඇති කේතයෙන් කෙරෙන්නේ කුමක් ද? සැකෙවින් කියුවොත් ඉන් සිදුවන්නේ මේ ක්‍රියාවන්:

  1. වෙබ් බ්‍රවුසරයට කැමරාවට පිවිසිය හැකි නම් වෙබ් පිටුවේ දැක්වෙන බොත්තම ක්ලික් කළ විට ක්‍රියාත්මක විය යුතු function එකක් බොත්තමට ඈදීම.
  2. COCO-SSD මොඩලය ලෝඩ් කිරීම සහ එය ලෝඩ් වී අවසානයේ වෙබ් පිටුවේ දැක්වෙන බොත්තම සක්‍රීය ලෙස පෙන්වීම.
  3. බොත්තම ක්ලික් කළ විට කැමරාවෙන් වීඩියෝ ප්‍රවාහය ලබාගැනීම සහ වීඩියෝ ප්‍රවාහයේ දත්ත සූදානම් විට ක්‍රියාත්මක විය යුතු function එකක් වීඩියෝ ප්‍රවාහයට ඈදීම.
  4. එම function එක ක්‍රියාත්මක වන විට වීඩියෝවේ පෙනෙන වස්තු COCO-SSD මොඩලය භාවිතයෙන් හඳුනාගැනීම සහ එම හඳුනාගත් වස්තු වටා කොටු ඇදීම.
  5. නැවත නැවතත් එම function එක ක්‍රියාත්මක වීමට සැලසීම.

ඉහත සඳහන් කළ දෑ script.js ගොනුවේ කේත මගින් ක්‍රියාත්මක වන ආකාරය ගැන දැනගැනීමට පහත දැක්වෙන කේතය සමඟ ලියා ඇති විචාරයන් කියවා බලන්න:

// index.html පිටුවේ id attribute මගින් දැක්වෙන element වෙත පිවිසීමට නියත (constants) කිහිපයක්
const video = document.getElementById('webcam');
const liveView = document.getElementById('liveView');
const demosSection = document.getElementById('demos');
const enableWebcamButton = document.getElementById('webcamButton');

// වෙබ් බ්‍රවුරසරයට කැමරාවට පිවිසිය හැකි දැයි පරික්ෂා කිරීමේ function එක
function getUserMediaSupported() {
  return !!(navigator.mediaDevices &&
    navigator.mediaDevices.getUserMedia);
}

// කැමරාවට පිවිසිය හැකි නම් enableWebcamButton බොත්තම ක්ලික් කළ විට
// enableCam() function එක ක්‍රියාත්මක විය යුතු බව
if (getUserMediaSupported()) {
  enableWebcamButton.addEventListener('click', enableCam);
} else {
  console.warn('getUserMedia() is not supported by your browser');
  alert('කැමරා පහසුකම නොමැති බව පෙනේ. ... https භාවිතා කර බලන්න.');
}

// enableWebcamButton බොත්තම ක්ලික් කළ විට මෙම function එක ක්‍රියාත්මක වේ.
function enableCam(event) {
  // COCO-SSD මොඩලය ලෝඩ් වීමට පෙර enableWebcamButton ක්ලික් කළහොත්
  // මෙම function එකේ ඉතිරි කොටස් වෙත නොයන්න.
  if (!model) {
    return;
  }
  
  // COCO-SSD මොඩලය ලෝඩ් වී ඇති විට enableWebcamButton බොත්තම
  // ක්ලික් කර ඇත. enableWebcamButton බොත්තම පිටුවේ පෙන්වීම නැවැත්වීම
  // සඳහා enableWebcamButton එකට 'removed' CSS ක්ලාස් එක එක්කරන්න.
  // style.css ගොනුවේ ඇති CSS කේතයන්ට අනුව මෙවිට enableWebcamButton
  // බොත්තම නොපෙනී යනු ඇත.
  event.target.classList.add('removed');  
  
  // කැමරාවෙන් වීඩියෝ ප්‍රවාහය ලබා ගැනීමට උවමනා බව දක්වන කේතය
  const constraints = {
    video: true
  };

  // කැමරාවෙන් වීඩියෝ ප්‍රවාහය ලබාගැනීම ආරම්භ කරන්න.
  // එම ප්‍රවාහය video element එක වෙත යොමු කරන්න.
  // වීඩියෝවේ දත්ත video element එකට යොමු වීම ආරම්භ වූ පසු
  // predictWebcam() function එක ක්‍රියාත්මක වන ලෙස වීඩියෝවට
  // predictWebcam() function එක අමුනන්න.
  navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
    video.srcObject = stream;
    video.addEventListener('loadeddata', predictWebcam);
  });
}

// COCO-SSD මොඩලය ලෝඩ් වූ විට මෙම විචල්‍යය හරහා එයට පිවිසිය හැක.
// තවම මොඩලය ලොඩ් කර නැති බැවින් undefined ලෙස දක්වන්න.
var model = undefined;

// index.html පිටුවේ ලෝඩ් කරන ලද COCO-SSD ආවරක කේතයේ (wrapper code) විස්තර කෙරී ඇති
// cocoSsd නම් object එක භාවිතා කර COCO-SSD යාන්ත්‍රික ඉගෙනුම් මොඩලය ලෝඩ් කරන්න.
// එසේ ලෝඩ් වූ පසු loadedModel මගින් දැක්වෙන එම මොඩලය model විචල්‍යය වෙත පැවරිය යුතු
// බව දක්වන්න. පිටුවේ ඇති බොත්තම සහ වීඩියෝව දැක්වෙන කොටසින් 'invisible' නම් CSS
// ක්ලාස් එක ඉවත් විය යුතු බව දක්වන්න.
cocoSsd.load().then(function (loadedModel) {
  model = loadedModel;
  // Show demo section now model is ready to use.
  demosSection.classList.remove('invisible');
});

// වස්තුවක් හඳුනාගැනීම කළ විට එම වස්තුව වටා පිටුවට එකතු කෙරෙන HTML div element
// මගින් කොටුවක් අදිනු ලැබේ. තවද හඳුනාගැනීම පිළිබඳ විස්තර දැක්වෙන HTML p element
// එකක් ද පිටුවට එකතු කෙරේ. එම element වල යොමු (references) රඳවා ගැනීමට විචල්‍යයක්
// නිර්වචනය කරන්න.
var children = [];

// enableWebcamButton බොත්තම ක්ලික් කළ විට ක්‍රියාත්මක වන enableCam() function එක මගින්
// මෙම predictWebcam() function එක ක්‍රියාත්මක වේ. මෙම function එක අවසානයේදී
// මෙම function එක නැවත ක්‍රියා කළ යුතු යැයි ද කේතනය කර ඇත. මෙම function එක තුළ
// COCO-SSD මොඩල භාවිතයෙන් වස්තු හඳුනාගැනීමට අදාළ කේතය පවතියි.
function predictWebcam() {

  // model.detect() function එක මගින් වීඩියෝවේ ඇති වස්තු හඳුනාගැනේ. වස්තු හඳුනාගැනීම
  // සිදු වූ පසු then() යන function එක මගින් ලබා දී ඇති function එක ක්‍රියාත්මක වේ.
  // එම හඳුනාගැනීම්වල විස්තර වෙත predictions විචල්‍යය හරහා පිවිසිය හැක.
  model.detect(video).then(function (predictions) {
  
    // පෙර හඳුනාගැනීම්වලට අදාළව HTML පිටුවට එක් කර ඇති කොටු සියල්ල ඉවත් කරන්න.
    for (let i = 0; i < children.length; i++) {
      liveView.removeChild(children[i]);
    }
    children.splice(0);
    
    // හඳුනාගැනීම් එකින් එක වෙත ගොස් කොටු අදින්න.
    for (let n = 0; n < predictions.length; n++) {
  
      // හඳුනාගැනීමේ විශ්වාසනීයත්වය 66% කට වඩා වැඩිනම් පමණක් කොටු ඇද සලකුණු කරමු.
      if (predictions[n].score > 0.66) {

        // පිටුවට එකතු කිරීමට p element එකක් සාදන්න.
        const p = document.createElement('p');
        
        // එම p element එකේ දැක්වෙන අන්තර්ගතය සකසන්න.
        p.innerText = predictions[n].class  + ' - විශ්වාසනීයත්වය:  ' 
            + Math.round(parseFloat(predictions[n].score) * 100)
            + '%';

        // එම p element එක දැක්විය යුතු තැන සහ එහි පළල සහ උස CSS මගින් විස්තර කරන්න.
        p.style = 'margin-left: ' + predictions[n].bbox[0] + 'px; margin-top: '
            + (predictions[n].bbox[1] - 10) + 'px; width: ' 
            + (predictions[n].bbox[2] - 10) + 'px; top: 0; left: 0;';


        // පිටුවට එකතු කිරීමට div element එකක් සාදන්න.
        const highlighter = document.createElement('div');

        // එම div element එකට CSS ක්ලාස් එකක් එකතු කරන්න. එහි විස්තර
        // style.css ගොනුවේ දැක්වේ.
        highlighter.setAttribute('class', 'highlighter');

        // එම div element එක දැක්විය යුතු තැන සහ එහි පළල සහ උස CSS මගින් විස්තර කරන්න.
        highlighter.style = 'left: ' + predictions[n].bbox[0] + 'px; top: '
            + predictions[n].bbox[1] + 'px; width: ' 
            + predictions[n].bbox[2] + 'px; height: '
            + predictions[n].bbox[3] + 'px;';


        // සෑදූ div සහ p element පිටුවේ liveView element එකට එකතු කරන්න.
        // සැ.යු. p element එක දෙවනුවට එක් කිරීම නිසා div element එකට උඩින් එය පෙනේ.
        liveView.appendChild(highlighter);
        liveView.appendChild(p);
        
        // නැවත හඳුනාගැනීමක් ආරම්භයේදී පිටුවට එකතු කළ div සහ p element
        // ඉවත් කිරීමට අවශ්‍ය බැවින් මතක තබා ගැනීම සඳහා ඒවායේ යොමු
        // children නම් ආරාවට (array) එක් කරන්න.
        children.push(highlighter);
        children.push(p);
      }
    }
    
    // වෙබ් බ්‍රවුසරය සූදානම් වූ පසු නැවත වස්තු හඳුනාගැනීම සඳහා predictWebcam() function එක
    // නැවත ක්‍රියාත්මක විය යුතු බව දක්වන්න.
    window.requestAnimationFrame(predictWebcam);
  });
}

මෙම ලිපියේ විස්තර කෙරෙන කැමරාව සාදාගැනීම සඳහා භාවිතා කෙරෙන COCO-SSD යාන්ත්‍රික ඉගෙනුම් මොඩලය වස්තු 80 ක් හඳුනාගැනීමට හැකි පෙර පුහුණු කළ මොඩලයක්. ඉන් හඳුනාගත හැකි වස්තු මොනවාද යන්න යම් අයෙකුට දැනගැනීමට උවමනා නම් භාවිතා කළ ආවරක කේතය අඩංගු GitHub ගබඩාවේ (repository) ඇති classes.ts නම් ගොනුවේ අන්තර්ගතය පරීක්ෂා කර බලන්න පුළුවන්.