2011-12-28 15 views
5

के साथ 2 डी छवि प्रसंस्करण मैं जेएस में एक साधारण फोटो संपादक बनाने का इरादा रखता हूं। मेरा मुख्य सवाल यह है कि क्या रीयल-टाइम में प्रस्तुत फ़िल्टर बनाना संभव है? उदाहरण के लिए, चमक और संतृप्ति समायोजित करना। मुझे बस एक 2 डी छवि चाहिए जहां मैं GPU का उपयोग कर फ़िल्टर लागू कर सकता हूं।वेब डीएल

मेरे द्वारा पढ़े गए सभी ट्यूटोरियल बहुत जटिल हैं और वास्तव में एपीआई का अर्थ नहीं बताते हैं। कृपया मुझे सही दिशा इंगित करें। धन्यवाद।

उत्तर

3

आप प्रत्येक ऑपरेशन के लिए कस्टम पिक्सेल शेडर बना सकते हैं जिसका आप उपयोग करना चाहते हैं। बस कुछ जीएलएसएल सीखें और मूल वेबजीएल को समझने के लिए "Learning WebGL" ट्यूटोरियल का पालन करें।

आप अपनी छवि को विभिन्न दृश्य शैलियों को नियंत्रित करने के लिए शामिल पैरामीटर को संशोधित करने वाले शेडर के साथ प्रस्तुत कर सकते हैं और फिर जब उपयोगकर्ता "ठीक" पर क्लिक करता है तो आप इसे अपनी वर्तमान छवि के रूप में संग्रहीत करने के लिए पिक्सल को वापस पढ़ सकते हैं।

बस क्रॉस डोमेन छवियों से बचने के लिए याद रखें, क्योंकि यह पिक्सल के रीडिंग बैक को अक्षम कर देगा।

इसके अलावा, शेडर संचालन पर त्वरित जानकारी के लिए quick reference card (पीडीएफ) देखें।

+0

अब मैं कैनवास पर एक सपाट छवि प्रस्तुत कर सकता हूं। क्या इसे 3 डी भाग के बिना लिखना संभव है? सीखने की सामग्री के लिए, मुझे वास्तव में क्या देखना चाहिए? ओपनजीएल ईएस, सामान्य ओपनजीएल, जीएलएसएल, वेबजीएल सभी अलग-अलग संस्करणों के साथ भी लगता है। –

+0

आप स्क्रीन बनाम क्वाड के साथ अपने बनावट को ऑरोग्राफिक प्रक्षेपण के साथ खींच सकते हैं। सीखने की सामग्रियों से आप जीएलएसएल पर ध्यान केंद्रित कर सकते हैं, जो भाषा आप अपने प्रभावों के लिए उपयोग करने जा रहे हैं – Chiguireitor

17

मैं एक ट्यूटोरियल लिखने और इसे अपने ब्लॉग पर पोस्ट करने जा रहा था, लेकिन मुझे नहीं पता कि मेरे पास कब खत्म होने का समय होगा, इसलिए मेरे पास Here's a more detailed set of posts on my blog है।

वेबजीएल वास्तव में एक रास्टराइजेशन लाइब्रेरी है। मैं विशेषताओं (डेटा की धाराओं), वर्दी (चर) में लेता हूं और उम्मीद करता हूं कि आप पिक्सेल के लिए 2 डी और रंग डेटा में "क्लिप स्पेस" निर्देशांक प्रदान करें।

यहाँ WebGL में 2 डी का एक सरल उदाहरण है (कुछ विवरण बाहर छोड़ दिया)

// Get A WebGL context 
var gl = canvas.getContext("experimental-webgl"); 

// setup GLSL program 
vertexShader = createShaderFromScriptElement(gl, "2d-vertex-shader"); 
fragmentShader = createShaderFromScriptElement(gl, "2d-fragment-shader"); 
program = createProgram(gl, vertexShader, fragmentShader); 
gl.useProgram(program); 

// look up where the vertex data needs to go. 
var positionLocation = gl.getAttribLocation(program, "a_position"); 

// Create a buffer and put a single clipspace rectangle in 
// it (2 triangles) 
var buffer = gl.createBuffer(); 
gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 
    -1.0, -1.0, 
    1.0, -1.0, 
    -1.0, 1.0, 
    -1.0, 1.0, 
    1.0, -1.0, 
    1.0, 1.0]), gl.STATIC_DRAW); 
gl.enableVertexAttribArray(positionLocation); 
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0); 

// draw 
gl.drawArrays(gl.TRIANGLES, 0, 6); 

यहाँ 2 shaders

<script id="2d-vertex-shader" type="x-shader/x-vertex"> 
attribute vec2 a_position; 
void main() { 
    gl_Position = vec4(a_position, 0, 1); 
} 
</script> 

<script id="2d-fragment-shader" type="x-shader/x-fragment"> 
void main() { 
    gl_FragColor = vec4(0,1,0,1); // green 
} 
</script> 

यह है एक हरे रंग की आयत कैनवास के पूरे आकार आकर्षित करेगा।

वेबजीएल में क्लिपटेस निर्देशांक प्रदान करने वाले वर्टेक्स शेडर प्रदान करना आपकी ज़िम्मेदारी है। कैनवास के आकार के बावजूद क्लिपस्पेस निर्देशांक हमेशा -1 से +1 तक जाते हैं। आप 3D यह shaders कि 3 डी में कनवर्ट 2D पर आपूर्ति करने के लिए आप पर निर्भर है क्योंकिWebGL केवल एक रैस्टराइज़ेशन एपीआई

एक साधारण उदाहरण में है चाहते हैं, आप एक आयत पास कर सकता है अगर आप पिक्सल में काम करना चाहते हैं कि क्लिप अंतरिक्ष निर्देशांक के बजाय पिक्सल का उपयोग करता है और शेडर

उदाहरण के लिए में अंतरिक्ष क्लिप में बदलने का:

<script id="2d-vertex-shader" type="x-shader/x-vertex"> 
attribute vec2 a_position; 

uniform vec2 u_resolution; 

void main() { 
    // convert the rectangle from pixels to 0.0 to 1.0 
    vec2 zeroToOne = a_position/u_resolution; 

    // convert from 0->1 to 0->2 
    vec2 zeroToTwo = zeroToOne * 2.0; 

    // convert from 0->2 to -1->+1 (clipspace) 
    vec2 clipSpace = zeroToTwo - 1.0; 

    gl_Position = vec4(clipSpace, 0, 1); 
} 
</script> 

अब हम डेटा को बदलने के द्वारा आयतों आकर्षित कर सकते हैं हम आपूर्ति

// set the resolution 
var resolutionLocation = gl.getUniformLocation(program, "u_resolution"); 
gl.uniform2f(resolutionLocation, canvas.width, canvas.height); 

// setup a rectangle from 10,20 to 80,30 in pixels 
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 
    10, 20, 
    80, 20, 
    10, 30, 
    10, 30, 
    80, 20, 
    80, 30]), gl.STATIC_DRAW); 

आप देखेंगे कि वेबजीएल नीचे दाएं कोने को 0,0 होने पर विचार करता है। इसे 2 डी ग्राफिक्स के लिए उपयोग किए जाने वाले अधिक पारंपरिक शीर्ष दाएं कोने के लिए प्राप्त करने के लिए हम केवल y समन्वय को फ़्लिप करते हैं।

gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); 

आप बनावट में उत्तीर्ण करने के लिए आवश्यक छवियों में हेरफेर करना चाहते हैं।उसी तरह कैनवास का आकार का प्रतिनिधित्व करती है clipspace निर्देशांक बनावट बनावट निर्देशांक कि 0 से करने के लिए 1.

<script id="2d-vertex-shader" type="x-shader/x-vertex"> 
attribute vec2 a_position; 
attribute vec2 a_texCoord; 

uniform vec2 u_resolution; 

varying vec2 v_texCoord; 

void main() { 
    // convert the rectangle from pixels to 0.0 to 1.0 
    vec2 zeroToOne = a_position/u_resolution; 

    // convert from 0->1 to 0->2 
    vec2 zeroToTwo = zeroToOne * 2.0; 

    // convert from 0->2 to -1->+1 (clipspace) 
    vec2 clipSpace = zeroToTwo - 1.0; 

    gl_Position = vec4(clipSpace, 0, 1); 

    // pass the texCoord to the fragment shader 
    // The GPU will interpolate this value between points. 
    v_texCoord = a_texCoord; 
} 
</script> 

<script id="2d-fragment-shader" type="x-shader/x-fragment"> 
precision float mediump; 

// our texture 
uniform sampler2D u_image; 

// the texCoords passed in from the vertex shader. 
varying vec2 v_texCoord; 

void main() { 
    gl_FragColor = texture2D(u_image, v_texCoord); 
} 
</script> 

जाना एक छवि आकर्षित करने के लिए द्वारा संदर्भित कर रहे हैं कर रहे हैं छवि लोड करने की आवश्यकता है और के बाद से है कि अतुल्यकालिक रूप से हम जरूरत होने से हमारे कोड को थोड़ा बदलने के लिए। सभी कोड हम था ले लो और एक समारोह कहा जाता है में रख "प्रस्तुत करना"

var image = new Image(); 
image.src = "http://someimage/on/our/server"; // MUST BE SAME DOMAIN!!! 
image.onload = function() { 
    render(); 
} 

function render() { 
    ... 
    // all the code we had before except gl.draw 


    // look up where the vertex data needs to go. 
    var texCoordLocation = gl.getAttribLocation(program, "a_texCoord"); 

    // provide texture coordinates for the rectangle. 
    var texCoordBuffer = gl.createBuffer(); 
    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer); 
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 
     1.0, 1.0, 
     0.0, 1.0, 
     0.0, 0.0, 
     1.0, 1.0, 
     0.0, 0.0, 
     1.0, 0.0]), gl.STATIC_DRAW); 
    gl.enableVertexAttribArray(texCoordLocation); 
    gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0); 

    var texture = gl.createTexture(); 
    gl.bindTexture(gl.TEXTURE_2D, texture); 
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 

    gl.draw(...) 

आप प्रसंस्करण आप बस अपने शेडर बदल छवि क्या करना चाहते हैं। उदाहरण, स्वैप लाल और नीला

void main() { 
    gl_FragColor = texture2D(u_image, v_texCoord).bgra; 
} 

या इसके आगे वाले पिक्सल के साथ मिश्रण करें।

uniform vec2 u_textureSize; 

void main() { 
    vec2 onePixel = vec2(1.0, 1.0)/u_textureSize; 
    gl_FragColor = (texture2D(u_image, v_texCoord) + 
        texture2D(u_image, v_texCoord + vec2(onePixel.x, 0.0)) + 
        texture2D(u_image, v_texCoord + vec2(-onePixel.x, 0.0)))/3.0; 
} 

और हम बनावट

var textureSizeLocation = gl.getUniformLocation(program, "u_textureSize"); 
... 
gl.uniform2f(textureSizeLocation, image.width, image.height); 

आदि के आकार में पारित करने के लिए ... एक घुमाव के नमूने के लिए नीचे दिए गए लिंक पर क्लिक करें पिछले है।

यहाँ एक अलग प्रगति

Draw Rect in Clip Space

Draw Rect in Pixels

Draw Rect with origin at top left

Draw a bunch of rects in different colors

Draw an image

साथ संस्करणों काम कर रहे हैं

Draw an image red and blue swapped

Draw an image with left and right pixels averaged

Draw an image with a 3x3 convolution

Draw an image with multiple effects

+0

विस्तृत स्पष्टीकरण के लिए धन्यवाद। मुझे यहां एक छोटी सी समस्या है, उम्मीद है कि आप इसके बारे में जानते हैं। http://stackoverflow.com/questions/8679596/extra-space-in-webgl-despite-same- आयाम –

+0

एक और सवाल। उपयोगकर्ता इनपुट के आधार पर मैं गतिशील रूप से कार्यों का संयोजन कैसे कॉल करूं? Exmaple के लिए, धुंध + संतृप्ति या सिर्फ अकेले sharpen। आपके उदाहरण में मैंने आपको कर्नेल का उपयोग करके देखा, जो कुछ मुझे समझ में नहीं आता है। धन्यवाद। –

+0

मुझे यहां से कर्नेल चीज़ मिली है (http://docs.gimp.org/en/plug-in-convmatrix.html) और यहां (http://www.codeproject.com/KB/graphics/ImageConvolution।एएसपीएक्स) उन्हें जोड़ने के लिए आपके सिर के ऊपर 2 चीजें हैं। # 1) आप फ्लाई पर शेडर्स उत्पन्न करने का प्रयास कर सकते हैं। # 2) आप फ्रेमबफर को प्रस्तुत कर सकते हैं और प्रत्येक चरण के लिए दोहरा सकते हैं – gman

0

बस glfx कोशिश (http://evanw.github.com/glfx.js/) मुझे लगता है कि यह वास्तव में आप क्या जरूरत है। आप पूर्वनिर्धारित शेडर्स के सेट का उपयोग कर सकते हैं या आसानी से अपना जोड़ सकते हैं;) आनंद लें! यह glfx के साथ बहुत आसान है!

<script src="glfx.js"></script> 
<script> 

window.onload = function() { 
    // try to create a WebGL canvas (will fail if WebGL isn't supported) 
    try { 
     var canvas = fx.canvas(); 
    } catch (e) { 
     alert(e); 
     return; 
    } 

    // convert the image to a texture 
    var image = document.getElementById('image'); 
    var texture = canvas.texture(image); 

    // apply the ink filter 
    canvas.draw(texture).ink(0.25).update(); 

    // replace the image with the canvas 
    image.parentNode.insertBefore(canvas, image); 
    image.parentNode.removeChild(image); 
}; 

</script> 
<img id="image" src="image.jpg">