परिचय
इमेज फ़िल्टर लिखने के लिए, 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 ]
);
हम मौजूदा फ़िल्टर को मिलाकर, इमेज के लिए ज़्यादा जटिल फ़िल्टर बना सकते हैं. उदाहरण के लिए, Sobel फ़िल्टर लिखें. सोबल फ़िल्टर, इमेज के वर्टिकल और हॉरिज़ॉन्टल ग्रेडिएंट का हिसाब लगाता है. साथ ही, इमेज में किनारों का पता लगाने के लिए, हिसाब लगाई गई इमेज को आपस में जोड़ता है. हम यहां सोबल फ़िल्टर को लागू करने के लिए, सबसे पहले इमेज को ग्रेस्केल में बदलते हैं. इसके बाद, हॉरिज़ॉन्टल और वर्टिकल ग्रेडिएंट लेते हैं. आखिर में, ग्रेडिएंट इमेज को जोड़कर फ़ाइनल इमेज बनाते हैं.
शब्दावली के बारे में बात करें, तो यहां "ग्रेडिएंट" का मतलब इमेज की जगह पर पिक्सल वैल्यू में बदलाव से है. अगर किसी पिक्सल के बायां पास में वैल्यू 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
}
साथ ही, ऐसे कई और शानदार कन्वोल्यूशन फ़िल्टर हैं, जिन्हें आज़माने के लिए आपका इंतज़ार किया जा रहा है. उदाहरण के लिए, ऊपर दिए गए कन्वलूशन टॉय में लैप्लेस फ़िल्टर का इस्तेमाल करें और देखें कि यह क्या करता है.
नतीजा
मुझे उम्मीद है कि इस छोटे से लेख से, एचटीएमएल कैनवस टैग का इस्तेमाल करके JavaScript में इमेज फ़िल्टर लिखने के बुनियादी सिद्धांतों को पेश करने में मदद मिली होगी. मेरा सुझाव है कि आप इमेज वाले कुछ और फ़िल्टर लगाएं, यह काफ़ी मज़ेदार है!
अगर आपको अपने फ़िल्टर की परफ़ॉर्मेंस बेहतर करनी है, तो इमेज प्रोसेस करने के लिए, आम तौर पर उन्हें WebGL फ़्रैगमेंट शेडर का इस्तेमाल करने के लिएपोर्ट किया जा सकता है. शेडर की मदद से, रीयल टाइम में ज़्यादातर आसान फ़िल्टर चलाए जा सकते हैं. इससे, वीडियो और ऐनिमेशन को पोस्ट-प्रोसेस करने के लिए, इनका इस्तेमाल किया जा सकता है.