ক্যানভাস সহ ইমেজ ফিল্টার

Ilmari Heikkinen

ভূমিকা

HTML5 ক্যানভাস উপাদান ইমেজ ফিল্টার লিখতে ব্যবহার করা যেতে পারে. আপনাকে যা করতে হবে তা হল একটি ক্যানভাসে একটি ছবি আঁকুন, ক্যানভাস পিক্সেলগুলি পড়ুন এবং সেগুলিতে আপনার ফিল্টার চালান৷ তারপরে আপনি ফলাফলটি একটি নতুন ক্যানভাসে লিখতে পারেন (বা হেক, শুধু পুরানোটি পুনরায় ব্যবহার করুন।)

সহজ শোনাচ্ছে? ভাল. এর ক্র্যাক করা যাক!

আসল পরীক্ষার ছবি
আসল পরীক্ষার ছবি

প্রসেসিং পিক্সেল

প্রথমে, ইমেজ পিক্সেল পুনরুদ্ধার করুন:

Filters = {};
Filters.getPixels = function(img) {
var c = this.getCanvas(img.width, img.height);
var ctx = c.getContext('2d');
ctx.drawImage(img);
return ctx.getImageData(0,0,c.width,c.height);
};

Filters.getCanvas = function(w,h) {
var c = document.createElement('canvas');
c.width = w;
c.height = h;
return c;
};

এর পরে, আমাদের ছবিগুলি ফিল্টার করার একটি উপায় দরকার। কিভাবে একটি filterImage পদ্ধতি যা একটি ফিল্টার এবং একটি ছবি নেয় এবং ফিল্টার করা পিক্সেল ফেরত দেয়?

Filters.filterImage = function(filter, image, var_args) {
var args = [this.getPixels(image)];
for (var i=2; i<arguments.length; i++) {
args.push(arguments[i]);
}
return filter.apply(null, args);
};

সহজ ফিল্টার চলমান

এখন যেহেতু আমাদের কাছে পিক্সেল প্রসেসিং পাইপলাইন একসাথে রাখা আছে, এখন কিছু সাধারণ ফিল্টার লেখার সময়। শুরু করতে, আসুন চিত্রটিকে গ্রেস্কেলে রূপান্তর করি।

Filters.grayscale = function(pixels, args) {
var d = pixels.data;
for (var i=0; i<d.length; i+=4) {
var r = d[i];
var g = d[i+1];
var b = d[i+2];
// CIE luminance for the RGB
// The human eye is bad at seeing red and blue, so we de-emphasize them.
var v = 0.2126*r + 0.7152*g + 0.0722*b;
d[i] = d[i+1] = d[i+2] = v
}
return pixels;
};

পিক্সেলগুলিতে একটি নির্দিষ্ট মান যোগ করে উজ্জ্বলতা সামঞ্জস্য করা যেতে পারে:

Filters.brightness = function(pixels, adjustment) {
var d = pixels.data;
for (var i=0; i<d.length; i+=4) {
d[i] += adjustment;
d[i+1] += adjustment;
d[i+2] += adjustment;
}
return pixels;
};

একটি ইমেজ থ্রেশহোল্ডিং এছাড়াও বেশ সহজ. আপনি শুধু একটি পিক্সেলের গ্রেস্কেল মানকে থ্রেশহোল্ড মানের সাথে তুলনা করুন এবং তার উপর ভিত্তি করে রঙ সেট করুন:

Filters.threshold = function(pixels, threshold) {
var d = pixels.data;
for (var i=0; i<d.length; i+=4) {
var r = d[i];
var g = d[i+1];
var b = d[i+2];
var v = (0.2126*r + 0.7152*g + 0.0722*b >= threshold) ? 255 : 0;
d[i] = d[i+1] = d[i+2] = v
}
return pixels;
};

সংঘটিত ছবি

কনভোলিউশন ফিল্টারগুলি ইমেজ প্রসেসিংয়ের জন্য খুব দরকারী জেনেরিক ফিল্টার। মূল ধারণা হল আপনি উৎস ইমেজ থেকে পিক্সেলের একটি আয়তক্ষেত্রের ওজনযুক্ত যোগফল নিন এবং আউটপুট মান হিসাবে এটি ব্যবহার করুন। কনভোলিউশন ফিল্টারগুলি ঝাপসা, তীক্ষ্ণ, এমবসিং, প্রান্ত সনাক্তকরণ এবং অন্যান্য জিনিসগুলির সম্পূর্ণ গুচ্ছের জন্য ব্যবহার করা যেতে পারে।

Filters.tmpCanvas = document.createElement('canvas');
Filters.tmpCtx = Filters.tmpCanvas.getContext('2d');

Filters.createImageData = function(w,h) {
return this.tmpCtx.createImageData(w,h);
};

Filters.convolute = function(pixels, weights, opaque) {
var side = Math.round(Math.sqrt(weights.length));
var halfSide = Math.floor(side/2);
var src = pixels.data;
var sw = pixels.width;
var sh = pixels.height;
// pad output by the convolution matrix
var w = sw;
var h = sh;
var output = Filters.createImageData(w, h);
var dst = output.data;
// go through the destination image pixels
var alphaFac = opaque ? 1 : 0;
for (var y=0; y<h; y++) {
for (var x=0; x<w; x++) {
  var sy = y;
  var sx = x;
  var dstOff = (y*w+x)*4;
  // calculate the weighed sum of the source image pixels that
  // fall under the convolution matrix
  var r=0, g=0, b=0, a=0;
  for (var cy=0; cy<side; cy++) {
    for (var cx=0; cx<side; cx++) {
      var scy = sy + cy - halfSide;
      var scx = sx + cx - halfSide;
      if (scy >= 0 && scy < sh && scx >= 0 && scx < sw) {
        var srcOff = (scy*sw+scx)*4;
        var wt = weights[cy*side+cx];
        r += src[srcOff] * wt;
        g += src[srcOff+1] * wt;
        b += src[srcOff+2] * wt;
        a += src[srcOff+3] * wt;
      }
    }
  }
  dst[dstOff] = r;
  dst[dstOff+1] = g;
  dst[dstOff+2] = b;
  dst[dstOff+3] = a + alphaFac*(255-a);
}
}
return output;
};

এখানে একটি 3x3 শার্পেন ফিল্টার। এটি কেন্দ্র পিক্সেলের উপর ওজন ফোকাস কিভাবে দেখুন. চিত্রের উজ্জ্বলতা বজায় রাখতে, ম্যাট্রিক্স মানগুলির যোগফল এক হওয়া উচিত।

Filters.filterImage(Filters.convolute, image,
[  0, -1,  0,
-1,  5, -1,
  0, -1,  0 ]
);

এখানে কনভোলিউশন ফিল্টারের আরেকটি উদাহরণ, বক্স ব্লার। বক্স ব্লার কনভোলিউশন ম্যাট্রিক্সের ভিতরে পিক্সেল মানের গড় আউটপুট করে। এটি করার উপায় হল NxN আকারের একটি কনভোলিউশন ম্যাট্রিক্স তৈরি করা যেখানে প্রতিটি ওজন 1 / (NxN)। এইভাবে ম্যাট্রিক্সের ভিতরের প্রতিটি পিক্সেল আউটপুট চিত্রে সমান পরিমাণে অবদান রাখে এবং ওজনের যোগফল এক।

Filters.filterImage(Filters.convolute, image,
[ 1/9, 1/9, 1/9,
1/9, 1/9, 1/9,
1/9, 1/9, 1/9 ]
);

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

পরিভাষা সম্পর্কে, এখানে "গ্রেডিয়েন্ট" মানে একটি চিত্র অবস্থানে পিক্সেল মান পরিবর্তন। যদি একটি পিক্সেলের মান 20 সহ একটি বাম প্রতিবেশী এবং 50 মান সহ একটি ডান প্রতিবেশী থাকে, তাহলে পিক্সেলের অনুভূমিক গ্রেডিয়েন্ট 30 হবে৷ উল্লম্ব গ্রেডিয়েন্টের একই ধারণা রয়েছে তবে উপরের এবং নীচের প্রতিবেশীগুলি ব্যবহার করে৷

var grayscale = Filters.filterImage(Filter.grayscale, image);
// Note that ImageData values are clamped between 0 and 255, so we need
// to use a Float32Array for the gradient values because they
// range between -255 and 255.
var vertical = Filters.convoluteFloat32(grayscale,
[ -1, 0, 1,
-2, 0, 2,
-1, 0, 1 ]);
var horizontal = Filters.convoluteFloat32(grayscale,
[ -1, -2, -1,
  0,  0,  0,
  1,  2,  1 ]);
var final_image = Filters.createImageData(vertical.width, vertical.height);
for (var i=0; i<final_image.data.length; i+=4) {
// make the vertical gradient red
var v = Math.abs(vertical.data[i]);
final_image.data[i] = v;
// make the horizontal gradient green
var h = Math.abs(horizontal.data[i]);
final_image.data[i+1] = h;
// and mix in some blue for aesthetics
final_image.data[i+2] = (v+h)/4;
final_image.data[i+3] = 255; // opaque alpha
}

এবং সেখানে অন্যান্য দুর্দান্ত কনভোলিউশন ফিল্টারগুলির একটি সম্পূর্ণ গুচ্ছ রয়েছে যা আপনি সেগুলি আবিষ্কার করার জন্য অপেক্ষা করছেন। উদাহরণস্বরূপ, উপরের কনভোলিউশন টয়টিতে একটি ল্যাপ্লেস ফিল্টার প্রয়োগ করার চেষ্টা করুন এবং দেখুন এটি কী করে।

উপসংহার

আমি আশা করি এই ছোট নিবন্ধটি এইচটিএমএল ক্যানভাস ট্যাগ ব্যবহার করে জাভাস্ক্রিপ্টে ইমেজ ফিল্টার লেখার প্রাথমিক ধারণাগুলি প্রবর্তন করতে কার্যকর ছিল৷ আমি আপনাকে যেতে এবং আরো কিছু ইমেজ ফিল্টার প্রয়োগ করতে উত্সাহিত করি, এটি বেশ মজার!

আপনার যদি আপনার ফিল্টারগুলি থেকে আরও ভাল পারফরম্যান্সের প্রয়োজন হয়, আপনি সাধারণত ইমেজ প্রসেসিং করতে WebGL ফ্র্যাগমেন্ট শেডার ব্যবহার করতে সেগুলিকে পোর্ট করতে পারেন৷ শেডারগুলির সাহায্যে, আপনি রিয়েলটাইমে সর্বাধিক সাধারণ ফিল্টারগুলি চালাতে পারেন, যা আপনাকে পোস্ট-প্রসেসিং ভিডিও এবং অ্যানিমেশনগুলির জন্য সেগুলি ব্যবহার করতে দেয়৷