JSARToolKit ব্যবহার করে অগমেন্টেড রিয়েলিটি অ্যাপ্লিকেশন লেখা

Ilmari Heikkinen

ভূমিকা

এই নিবন্ধটি ওয়েবে অগমেন্টেড রিয়েলিটি অ্যাপ্লিকেশন করতে WebRTC getUserMedia API-এর সাথে JSARToolKit লাইব্রেরি ব্যবহার করার বিষয়ে। রেন্ডারিংয়ের জন্য, আমি WebGL ব্যবহার করছি এটির অফার বর্ধিত কর্মক্ষমতার কারণে। এই নিবন্ধের শেষ ফলাফল হল একটি ডেমো অ্যাপ্লিকেশন যা ওয়েবক্যাম ভিডিওতে একটি বর্ধিত বাস্তবতা চিহ্নিতকারীর উপরে একটি 3D মডেল রাখে।

JSARToolKit হল জাভাস্ক্রিপ্টের জন্য একটি অগমেন্টেড রিয়েলিটি লাইব্রেরি। এটি একটি ওপেন সোর্স লাইব্রেরি যা GPL-এর অধীনে প্রকাশিত হয়েছে এবং ফ্ল্যাশ FLARToolKit- এর একটি সরাসরি পোর্ট যা আমি Mozilla Remixing Reality ডেমোর জন্য তৈরি করেছি। FLARToolKit নিজেই জাভা NyARToolKit- এর পোর্ট, যা C ARToolKit- এর একটি পোর্ট। দীর্ঘ পথ, কিন্তু আমরা এখানে.

JSARToolKit ক্যানভাস উপাদানের উপর কাজ করে। এটিকে ক্যানভাসের বাইরের ছবিটি পড়তে হবে, তাই ছবিটিকে পৃষ্ঠার মতো একই উৎস থেকে আসতে হবে বা একই-অরিজিন নীতি পেতে CORS ব্যবহার করতে হবে । সংক্ষেপে, আপনি যে ইমেজ বা ভিডিও উপাদানটিকে '' বা 'anonymous' তে টেক্সচার হিসাবে ব্যবহার করতে চান তার উপর crossOrigin -property সেট করুন।

আপনি যখন বিশ্লেষণের জন্য JSARToolKit-এ একটি ক্যানভাস পাস করেন, JSARToolKit ছবিতে পাওয়া AR মার্কারগুলির একটি তালিকা এবং সংশ্লিষ্ট রূপান্তর ম্যাট্রিক্স প্রদান করে। একটি মার্কারের উপরে একটি 3D অবজেক্ট আঁকতে, আপনি যে 3D রেন্ডারিং লাইব্রেরি ব্যবহার করছেন তাতে আপনি ট্রান্সফর্মেশন ম্যাট্রিক্স পাস করবেন যাতে ম্যাট্রিক্স ব্যবহার করে আপনার অবজেক্ট রূপান্তরিত হয়। তারপর, আপনার ওয়েবজিএল দৃশ্যে ভিডিও ফ্রেমটি আঁকুন এবং এর উপরে বস্তুটি আঁকুন এবং আপনি যেতে পারবেন।

JSARToolKit ব্যবহার করে ভিডিও বিশ্লেষণ করতে, একটি ক্যানভাসে ভিডিওটি আঁকুন, তারপর JSARToolKit-এ ক্যানভাসটি দিন। প্রতিটি ফ্রেমের জন্য এটি করুন এবং আপনি ভিডিও এআর ট্র্যাকিং পেয়েছেন। JSARToolKit আধুনিক জাভাস্ক্রিপ্ট ইঞ্জিনে যথেষ্ট দ্রুত এটি রিয়েলটাইমে এমনকি 640x480 ভিডিও ফ্রেমেও করতে পারে। যাইহোক, ভিডিও ফ্রেম যত বড় হবে, প্রক্রিয়া করতে তত বেশি সময় লাগবে। একটি ভাল ভিডিও ফ্রেমের আকার হল 320x240, কিন্তু আপনি যদি ছোট মার্কার বা একাধিক মার্কার ব্যবহার করার আশা করেন তবে 640x480 বাঞ্ছনীয়৷

ডেমো

ওয়েবক্যাম ডেমো দেখতে, আপনার ব্রাউজারে WebRTC সক্ষম করতে হবে (Chrome-এ, about:flags এ যান এবং MediaStream সক্ষম করুন)। আপনাকে নীচের AR মার্কারটিও প্রিন্ট করতে হবে। আপনি আপনার ফোন বা ট্যাবলেটে মার্কার চিত্রটি খোলার এবং ওয়েবক্যামে দেখানোর চেষ্টা করতে পারেন৷

এআর মার্কার।
এআর মার্কার।

JSARToolKit সেট আপ করা হচ্ছে

JSARToolKit API অনেকটা জাভা-এর মতো, তাই এটি ব্যবহার করার জন্য আপনাকে কিছু বিকৃতি করতে হবে। মূল ধারণা হল আপনার কাছে একটি ডিটেক্টর অবজেক্ট আছে যা একটি রাস্টার অবজেক্টে কাজ করে। ডিটেক্টর এবং রাস্টারের মধ্যে একটি ক্যামেরা প্যারামিটার অবজেক্ট যা রাস্টার স্থানাঙ্ককে ক্যামেরা স্থানাঙ্কে রূপান্তরিত করে। ডিটেক্টর থেকে চিহ্নিত মার্কারগুলি পেতে, আপনি তাদের উপর পুনরাবৃত্তি করুন এবং তাদের রূপান্তর ম্যাট্রিক্সগুলি আপনার কোডে অনুলিপি করুন।

প্রথম ধাপ হল রাস্টার অবজেক্ট, ক্যামেরা প্যারামিটার অবজেক্ট এবং ডিটেক্টর অবজেক্ট তৈরি করা।

// Create a RGB raster object for the 2D canvas.
// JSARToolKit uses raster objects to read image data.
// Note that you need to set canvas.changed = true on every frame.
var raster = new NyARRgbRaster_Canvas2D(canvas);

// FLARParam is the thing used by FLARToolKit to set camera parameters.
// Here we create a FLARParam for images with 320x240 pixel dimensions.
var param = new FLARParam(320, 240);

// The FLARMultiIdMarkerDetector is the actual detection engine for marker detection.
// It detects multiple ID markers. ID markers are special markers that encode a number.
var detector = new FLARMultiIdMarkerDetector(param, 120);

// For tracking video set continue mode to true. In continue mode, the detector
// tracks markers across multiple frames.
detector.setContinueMode(true);

// Copy the camera perspective matrix from the FLARParam to the WebGL library camera matrix.
// The second and third parameters determine the zNear and zFar planes for the perspective matrix.
param.copyCameraMatrix(display.camera.perspectiveMatrix, 10, 10000);

ওয়েবক্যাম অ্যাক্সেস করতে getUserMedia ব্যবহার করে

এর পরে, আমি একটি ভিডিও উপাদান তৈরি করতে যাচ্ছি যা WebRTC API-এর মাধ্যমে ওয়েবক্যাম ভিডিও পাচ্ছে। প্রাক-রেকর্ড করা ভিডিওগুলির জন্য, শুধুমাত্র ভিডিও URL-এ ভিডিওটির উত্স বৈশিষ্ট্য সেট করুন৷ আপনি যদি স্থির চিত্রগুলি থেকে মার্কার সনাক্তকরণ করছেন, আপনি একইভাবে একটি চিত্র উপাদান ব্যবহার করতে পারেন।

যেহেতু WebRTC এবং getUserMedia এখনও নতুন উদীয়মান প্রযুক্তি, তাই আপনাকে বৈশিষ্ট্যগুলি সনাক্ত করতে হবে। আরও বিশদ বিবরণের জন্য, HTML5-এ অডিও এবং ভিডিও ক্যাপচার করার বিষয়ে এরিক বিডেলম্যানের নিবন্ধটি দেখুন।

var video = document.createElement('video');
video.width = 320;
video.height = 240;

var getUserMedia = function(t, onsuccess, onerror) {
  if (navigator.getUserMedia) {
    return navigator.getUserMedia(t, onsuccess, onerror);
  } else if (navigator.webkitGetUserMedia) {
    return navigator.webkitGetUserMedia(t, onsuccess, onerror);
  } else if (navigator.mozGetUserMedia) {
    return navigator.mozGetUserMedia(t, onsuccess, onerror);
  } else if (navigator.msGetUserMedia) {
    return navigator.msGetUserMedia(t, onsuccess, onerror);
  } else {
    onerror(new Error("No getUserMedia implementation found."));
  }
};

var URL = window.URL || window.webkitURL;
var createObjectURL = URL.createObjectURL || webkitURL.createObjectURL;
if (!createObjectURL) {
  throw new Error("URL.createObjectURL not found.");
}

getUserMedia({'video': true},
  function(stream) {
    var url = createObjectURL(stream);
    video.src = url;
  },
  function(error) {
    alert("Couldn't access webcam.");
  }
);

চিহ্নিতকারী সনাক্তকরণ

একবার আমাদের ডিটেক্টর এ-ওকে চললে, আমরা AR ম্যাট্রিক্স সনাক্ত করতে এটিকে ছবি খাওয়ানো শুরু করতে পারি। প্রথমে রাস্টার অবজেক্টের ক্যানভাসে ছবিটি আঁকুন, তারপর রাস্টার অবজেক্টে ডিটেক্টর চালান। ডিটেক্টর চিত্রটিতে পাওয়া মার্কারগুলির সংখ্যা ফেরত দেয়।

// Draw the video frame to the raster canvas, scaled to 320x240.
canvas.getContext('2d').drawImage(video, 0, 0, 320, 240);

// Tell the raster object that the underlying canvas has changed.
canvas.changed = true;

// Do marker detection by using the detector object on the raster object.
// The threshold parameter determines the threshold value
// for turning the video frame into a 1-bit black-and-white image.
//
var markerCount = detector.detectMarkerLite(raster, threshold);

শেষ ধাপ হল শনাক্ত করা মার্কারগুলির মাধ্যমে পুনরাবৃত্তি করা এবং তাদের রূপান্তর ম্যাট্রিক্সগুলি পাওয়া। আপনি চিহ্নিতকারীর উপরে 3D বস্তু রাখার জন্য রূপান্তর ম্যাট্রিক্স ব্যবহার করেন।

// Create a NyARTransMatResult object for getting the marker translation matrices.
var resultMat = new NyARTransMatResult();

var markers = {};

// Go through the detected markers and get their IDs and transformation matrices.
for (var idx = 0; idx < markerCount; idx++) {
  // Get the ID marker data for the current marker.
  // ID markers are special kind of markers that encode a number.
  // The bytes for the number are in the ID marker data.
  var id = detector.getIdMarkerData(idx);

  // Read bytes from the id packet.
  var currId = -1;
  // This code handles only 32-bit numbers or shorter.
  if (id.packetLength <= 4) {
    currId = 0;
    for (var i = 0; i &lt; id.packetLength; i++) {
      currId = (currId << 8) | id.getPacketData(i);
    }
  }

  // If this is a new id, let's start tracking it.
  if (markers[currId] == null) {
    markers[currId] = {};
  }
  // Get the transformation matrix for the detected marker.
  detector.getTransformMatrix(idx, resultMat);

  // Copy the result matrix into our marker tracker object.
  markers[currId].transform = Object.asCopy(resultMat);
}

ম্যাট্রিক্স ম্যাপিং

এখানে JSARToolKit ম্যাট্রিক্সগুলিকে glMatrix ম্যাট্রিক্সে অনুলিপি করার কোড রয়েছে (যা শেষ চারটি উপাদানের অনুবাদ কলাম সহ 16-এলিমেন্ট ফ্লোটঅ্যারে )। এটি জাদু দ্বারা কাজ করে (পড়ুন: আমি জানি না কিভাবে ARToolKit ম্যাট্রিক্স সেটআপ করা হয়। উল্টানো Y-অক্ষ আমার অনুমান।) যাইহোক, এই বিট সাইন-রিভার্সিং ভুডু একটি JSARToolKit ম্যাট্রিক্সকে একটি glMatrix এর মতোই কাজ করে।

লাইব্রেরিটিকে অন্য লাইব্রেরির সাথে ব্যবহার করতে, যেমন Three.js, আপনাকে একটি ফাংশন লিখতে হবে যা ARToolKit ম্যাট্রিক্সকে লাইব্রেরির ম্যাট্রিক্স ফরম্যাটে রূপান্তর করে। এছাড়াও আপনাকে FLARParam.copyCameraMatrix পদ্ধতিতে হুক করতে হবে। copyCameraMatrix পদ্ধতি FLARParam পরিপ্রেক্ষিত ম্যাট্রিক্সকে একটি glMatrix-শৈলী ম্যাট্রিক্সে লেখে।

function copyMarkerMatrix(arMat, glMat) {
  glMat[0] = arMat.m00;
  glMat[1] = -arMat.m10;
  glMat[2] = arMat.m20;
  glMat[3] = 0;
  glMat[4] = arMat.m01;
  glMat[5] = -arMat.m11;
  glMat[6] = arMat.m21;
  glMat[7] = 0;
  glMat[8] = -arMat.m02;
  glMat[9] = arMat.m12;
  glMat[10] = -arMat.m22;
  glMat[11] = 0;
  glMat[12] = arMat.m03;
  glMat[13] = -arMat.m13;
  glMat[14] = arMat.m23;
  glMat[15] = 1;
}

Three.js ইন্টিগ্রেশন

Three.js একটি জনপ্রিয় জাভাস্ক্রিপ্ট 3D ইঞ্জিন। আমি কিভাবে Three.js-এ JSARToolKit আউটপুট ব্যবহার করব তা দেখতে যাচ্ছি। আপনার তিনটি জিনিসের প্রয়োজন: একটি পূর্ণ স্ক্রিন কোয়াড যেখানে ভিডিও চিত্রটি আঁকা হয়েছে, একটি এফএলআরপারম দৃষ্টিকোণ ম্যাট্রিক্স সহ একটি ক্যামেরা এবং এটির রূপান্তর হিসাবে চিহ্নিতকারী ম্যাট্রিক্স সহ একটি বস্তু৷ আমি আপনাকে নীচের কোডে ইন্টিগ্রেশনের মাধ্যমে নিয়ে যাব।

// I'm going to use a glMatrix-style matrix as an intermediary.
// So the first step is to create a function to convert a glMatrix matrix into a Three.js Matrix4.
THREE.Matrix4.prototype.setFromArray = function(m) {
  return this.set(
    m[0], m[4], m[8], m[12],
    m[1], m[5], m[9], m[13],
    m[2], m[6], m[10], m[14],
    m[3], m[7], m[11], m[15]
  );
};

// glMatrix matrices are flat arrays.
var tmp = new Float32Array(16);

// Create a camera and a marker root object for your Three.js scene.
var camera = new THREE.Camera();
scene.add(camera);

var markerRoot = new THREE.Object3D();
markerRoot.matrixAutoUpdate = false;

// Add the marker models and suchlike into your marker root object.
var cube = new THREE.Mesh(
  new THREE.CubeGeometry(100,100,100),
  new THREE.MeshBasicMaterial({color: 0xff00ff})
);
cube.position.z = -50;
markerRoot.add(cube);

// Add the marker root to your scene.
scene.add(markerRoot);

// Next we need to make the Three.js camera use the FLARParam matrix.
param.copyCameraMatrix(tmp, 10, 10000);
camera.projectionMatrix.setFromArray(tmp);


// To display the video, first create a texture from it.
var videoTex = new THREE.Texture(videoCanvas);

// Then create a plane textured with the video.
var plane = new THREE.Mesh(
  new THREE.PlaneGeometry(2, 2, 0),
  new THREE.MeshBasicMaterial({map: videoTex})
);

// The video plane shouldn't care about the z-buffer.
plane.material.depthTest = false;
plane.material.depthWrite = false;

// Create a camera and a scene for the video plane and
// add the camera and the video plane to the scene.
var videoCam = new THREE.Camera();
var videoScene = new THREE.Scene();
videoScene.add(plane);
videoScene.add(videoCam);

...

// On every frame do the following:
function tick() {
  // Draw the video frame to the canvas.
  videoCanvas.getContext('2d').drawImage(video, 0, 0);
  canvas.getContext('2d').drawImage(videoCanvas, 0, 0, canvas.width, canvas.height);

  // Tell JSARToolKit that the canvas has changed.
  canvas.changed = true;

  // Update the video texture.
  videoTex.needsUpdate = true;

  // Detect the markers in the video frame.
  var markerCount = detector.detectMarkerLite(raster, threshold);
  for (var i=0; i&lt;markerCount; i++) {
    // Get the marker matrix into the result matrix.
    detector.getTransformMatrix(i, resultMat);

    // Copy the marker matrix to the tmp matrix.
    copyMarkerMatrix(resultMat, tmp);

    // Copy the marker matrix over to your marker root object.
    markerRoot.matrix.setFromArray(tmp);
  }

  // Render the scene.
  renderer.autoClear = false;
  renderer.clear();
  renderer.render(videoScene, videoCam);
  renderer.render(scene, camera);
}

সারসংক্ষেপ

এই প্রবন্ধে আমরা JSARToolKit এর মূল বিষয়গুলো দেখেছি। এখন আপনি জাভাস্ক্রিপ্টের সাথে অগমেন্টেড রিয়েলিটি অ্যাপ্লিকেশন ব্যবহার করে আপনার নিজস্ব ওয়েবক্যাম তৈরি করতে প্রস্তুত৷

JSARToolKit কে Three.js-এর সাথে একীভূত করা কিছুটা ঝামেলার, কিন্তু এটা অবশ্যই সম্ভব। আমি 100% নিশ্চিত নই যে আমি আমার ডেমোতে এটি ঠিক করছি কিনা, তাই আপনি যদি ইন্টিগ্রেশন অর্জনের আরও ভাল উপায় জানেন তবে দয়া করে আমাকে জানান। প্যাচ স্বাগত জানাই :)

তথ্যসূত্র