8 Replies Latest reply on Aug 9, 2011 7:31 AM by chauffeurdevan

    Can PB can calcute the bounding box as the needed region in AE?

    chauffeurdevan Level 2

      Hi,

       

      I wrote many small pixel bender that I use mainly in AE. However I need them to be as efficient as possible, so I wonder if Pixel Bender can obtain the bounding box of an image input as the needed region. This way, it will not calculate an entire frame when there is only a few pixels in the frame.

       

      Thanks

       

       

      Jocelyn Tremblay

        • 1. Re: Can PB can calcute the bounding box as the needed region in AE?
          unique_screenname_here Level 3

          A Pixel Bender float2 parameter can be specified to be of "inputSize" type which tells the filter that the parameter is the size (width and height) of one of the input images. I believe AfterEffects supports this parameter metadata but didn't do a test to verify. Take a look at page 70 of the Pixel Bender Developer's Guide for more info. A word of warning, I caution against using this parameter metadata as it makes your filters fragile and opens them up to bugs especially when the filter is used as part of a larger filter graph. It's better to just specify reasonable needed and changed functions for your filter and let the runtime decide how best to optimize.

          • 2. Re: Can PB can calcute the bounding box as the needed region in AE?
            chauffeurdevan Level 2

            Hi,

             

            This is not what I'm looking for. The goal here is to process the smallet region of pixel by finding automaticaly where there is only visible pixels. For example, I have some keyed green-screen stuff that is small and moving and process only a small rectangle of pixels and not the entire frame to save a lot of processing. I could try to animate a region by hand, but the goal of a computer is to help with that.

             

            In flash, I would have used something like http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapDat a.html#getColorBoundsRect() applied on the alpha channel. However, in after effects, there is inthe expressions a sampleImage where I could do that, but it is in JavaScipt, so there is no gain in doing it over 1920x1080 pixels - the computer will freeze or crash.

             

            So i need a way to find the smallest rectangle of visible pixels and process it. Ideally using the neededRegion in PixelBender.

             

            Thanks

            • 3. Re: Can PB can calcute the bounding box as the needed region in AE?
              unique_screenname_here Level 3

              The only way, in Pixel Bender, to affect the number of pixels processed is via Pixel Bender's region reasoning functions. The only way to get the size of the input image is via an "inputSize" parameter as I mentioned in my previous post. You can get the domain-of-definition of an input image via the dod function but the domain-of-definition and image size are not necessarily equivalent. Please see the Pixel Bender Reference and Pixel Bender Developer's Guide for more information.

               

              You could try mimicking the behavior of getColorBoundsRect in a Pixel Bender Filter and then wiring that filter in a graph upstream of the filters that are doing more intensive processing. It's hard to say whether that will do what you want.

              • 4. Re: Can PB can calcute the bounding box as the needed region in AE?
                chauffeurdevan Level 2

                Hi,

                 

                I got something working, like you suggested, using a graph. Right now, I'm not gaining that much speed for what I want to do, as to find the BoundingBox is pretty hungry. So if anybody have any idea to optimize it, let me know.

                 

                Here is a prettty basic graph that just draw a rectangle covering the bounding box of an image. Feed it something with some alpha.

                 

                Thanks

                 

                Jocelyn Tremblay

                 

                BoundingBoxExperience.pbg

                <?xml version="1.0" encoding="utf-8"?>
                <graph name = "BoundingBoxExperience" xmlns="http://ns.adobe.com/PixelBenderGraph/1.0">
                    <metadata name = "namespace" value =  "com.jocelyntremblay"/>
                    <metadata name = "vendor" value = "Jocelyn Tremblay" />
                    <metadata name = "version" type = "int" value = "1" />

                    <!-- Image inputs and outputs of the graph -->
                    <inputImage type = "image4" name = "src" />
                    <outputImage type = "image4" name = "dst" />
                  
                    <!-- Graph parameters -->
                    <parameter type="float2" name="sourceSize" >
                        <metadata name="parameterType" value="inputSize"/>
                        <metadata name="inputSizeName" value="src" />
                    </parameter>

                     <!-- Embedded kernel -->
                     <kernel>
                      <![CDATA[
                         <languageVersion : 1.0;>
                         kernel getBoundingBox
                         <  
                            namespace:"com.jocelyntremblay";
                            vendor:"Jocelyn Tremblay";
                            version:1;
                         >{
                            input image4 src;
                            output float4 dst;
                           
                            parameter float2 sourceSize
                            <
                                parameterType : "inputSize";
                                inputSizeName : "src";
                            >;
                   
                            region changed(region inputRegion, imageRef inputIndex){
                                return region(float4(0, 0, 1, 1));
                            }
                           
                            void evaluatePixel(){
                                float4 boundingBox = float4(99999., 99999., 0., 0.);
                                float i = 0.;
                                float j;
                                pixel4 pix;
                                for (i=0.; i < sourceSize.x; i++){
                                    j = 0.;
                                    for (j; j < sourceSize.y; j++){
                                        pix = sampleNearest(src, float2(i, j));
                                        if (pix.a > 0.){
                                            boundingBox.x = i < boundingBox.x ? i : boundingBox.x;
                                            boundingBox.y = j < boundingBox.y ? j : boundingBox.y;
                                            boundingBox.z = i > boundingBox.z ? i : boundingBox.z;
                                            boundingBox.w = j > boundingBox.w ? j : boundingBox.w;
                                        }
                                    }
                                }
                                dst = boundingBox;
                            }
                         }
                      ]]>
                     </kernel>
                     <kernel>
                      <![CDATA[
                         <languageVersion : 1.0;>
                         kernel drawBoundingBox
                         <  
                            namespace:"com.jocelyntremblay";
                            vendor:"Jocelyn Tremblay";
                            version:1;
                         >{
                            input image4 src;
                            input image4 boundingBox;
                            output float4 dst;

                           
                            void evaluatePixel(){
                                float4 rectangle = sampleNearest(boundingBox, float2(0, 0));
                                if ((outCoord().x > rectangle.x)&&(outCoord().y > rectangle.y)&&(outCoord().x < rectangle.z)&&(outCoord().y < rectangle.w)){
                                                //process
                                                dst = float4(1., 0, 0, 1);
                                }
                                else{
                                    //do not process
                                    dst = float4(0.);
                                }
                            }
                         }
                      ]]>
                     </kernel>

                    <!-- Instances of the nodes -->
                    <node id = "getBoundingBox" name ="getBoundingBox" namespace = "com.jocelyntremblay" vendor = "Jocelyn Tremblay" version ="1">
                    <evaluateParameters>
                            <![CDATA[void evaluateParameters() {
                                getBoundingBox::sourceSize = sourceSize;
                            }]]>
                        </evaluateParameters>
                    </node>
                    <node id = "drawBoundingBox" name ="drawBoundingBox" namespace = "com.jocelyntremblay" vendor = "Jocelyn Tremblay" version ="1"/>

                    <!-- Connect the graph -->
                    <connect fromImage = "src" toNode = "getBoundingBox" toInput = "src" />
                    <connect fromImage = "src" toNode = "drawBoundingBox" toInput = "src" />
                    <connect fromNode = "getBoundingBox" fromOutput = "dst" toNode = "drawBoundingBox" toInput = "boundingBox" />
                     <connect fromNode = "drawBoundingBox" fromOutput = "dst" toImage = "dst" />
                </graph>

                • 5. Re: Can PB can calcute the bounding box as the needed region in AE?
                  unique_screenname_here Level 3

                  Would you please post an AE project that demos this filter working as expected. It looks to me as though AE is not passing in the image size to the sourceSize parameter so it's not yet clear to me how this is working for you.

                  • 6. Re: Can PB can calcute the bounding box as the needed region in AE?
                    chauffeurdevan Level 2

                    Hi,

                     

                    Yeah, I just try it in AE and the sourceSize thing doesn't work in it. I discovered it last night and it is working in the toolkit didn't know about not working in AE. So I'll have to put back the regular float2 to all the filter I changed since yesterday.

                     

                    Oh. I just found that by setting the graph to a regular float2 parameter, but by setting the kernel to parameterType : "inputSize"; the composition size is automaticaly detected.

                     

                    So here is a working version :

                     

                    Header 1

                    <?xml version="1.0" encoding="utf-8"?>
                    <graph name = "BoundingBoxExperience" xmlns="http://ns.adobe.com/PixelBenderGraph/1.0">
                        <metadata name = "namespace" value =  "com.jocelyntremblay"/>
                        <metadata name = "vendor" value = "Jocelyn Tremblay" />
                        <metadata name = "version" type = "int" value = "1" />

                        <!-- Image inputs and outputs of the graph -->
                        <inputImage type = "image4" name = "src" />
                        <outputImage type = "image4" name = "dst" />
                      
                        <!-- Graph parameters -->
                        <parameter type="float2" name="sourceSize" >
                            <metadata name="minValue" type="float2" value="1"/>
                            <metadata name="maxValue" type="float2" value="4096" />
                            <metadata name="defaultValue" type="float2" value="1920., 720." />
                            <metadata name="aeUIControl" value="aePoint" />
                            <metadata name="aePointRelativeDefaultValue" type="float2" value="1, 1" />
                        </parameter>

                         <!-- Embedded kernel -->
                         <kernel>
                          <![CDATA[
                             <languageVersion : 1.0;>
                             kernel getBoundingBox
                             <  
                                namespace:"com.jocelyntremblay";
                                vendor:"Jocelyn Tremblay";
                                version:1;
                             >{
                                input image4 src;
                                output float4 dst;
                               
                                parameter float2 sourceSize
                                <
                                    parameterType : "inputSize";
                                    inputSizeName : "src";
                                >;
                       
                                region changed(region inputRegion, imageRef inputIndex){
                                    return region(float4(0, 0, 1, 1));
                                }
                               
                                void evaluatePixel(){
                                    float4 boundingBox = float4(99999., 99999., 0., 0.);
                                    float i = 0.;
                                    float j;
                                    pixel4 pix;
                                    for (i=0.; i < sourceSize.x; i++){
                                        j = 0.;
                                        for (j; j < sourceSize.y; j++){
                                            pix = sampleNearest(src, float2(i, j));
                                            if (pix.a > 0.){
                                                boundingBox.x = i < boundingBox.x ? i : boundingBox.x;
                                                boundingBox.y = j < boundingBox.y ? j : boundingBox.y;
                                                boundingBox.z = i > boundingBox.z ? i : boundingBox.z;
                                                boundingBox.w = j > boundingBox.w ? j : boundingBox.w;
                                            }
                                        }
                                    }
                                    dst = boundingBox;
                                }
                             }
                          ]]>
                         </kernel>
                         <kernel>
                          <![CDATA[
                             <languageVersion : 1.0;>
                             kernel drawBoundingBox
                             <  
                                namespace:"com.jocelyntremblay";
                                vendor:"Jocelyn Tremblay";
                                version:1;
                             >{
                                input image4 src;
                                input image4 boundingBox;
                                output float4 dst;

                               
                                void evaluatePixel(){
                                    float4 rectangle = sampleNearest(boundingBox, float2(0, 0));
                                    if ((outCoord().x > rectangle.x)&&(outCoord().y > rectangle.y)&&(outCoord().x < rectangle.z)&&(outCoord().y < rectangle.w)){
                                                    //process
                                                    dst = float4(1., 0, 0, 1);
                                    }
                                    else{
                                        //do not process
                                        dst = float4(0.);
                                    }
                                }
                             }
                          ]]>
                         </kernel>

                        <!-- Instances of the nodes -->
                        <node id = "getBoundingBox" name ="getBoundingBox" namespace = "com.jocelyntremblay" vendor = "Jocelyn Tremblay" version ="1">
                        <evaluateParameters>
                                <![CDATA[void evaluateParameters() {
                                    getBoundingBox::sourceSize = sourceSize;
                                }]]>
                            </evaluateParameters>
                        </node>
                        <node id = "drawBoundingBox" name ="drawBoundingBox" namespace = "com.jocelyntremblay" vendor = "Jocelyn Tremblay" version ="1"/>

                        <!-- Connect the graph -->
                        <connect fromImage = "src" toNode = "getBoundingBox" toInput = "src" />
                        <connect fromImage = "src" toNode = "drawBoundingBox" toInput = "src" />
                        <connect fromNode = "getBoundingBox" fromOutput = "dst" toNode = "drawBoundingBox" toInput = "boundingBox" />
                         <connect fromNode = "drawBoundingBox" fromOutput = "dst" toImage = "dst" />
                    </graph>

                    • 7. Re: Can PB can calcute the bounding box as the needed region in AE?
                      unique_screenname_here Level 3

                      Hey good find about inputSize and AE. So is the filter is doing what you want but it's just not fast enough correct? Would you post a filtered image and an unfiltered image so I can get a better idea of the expected result. Maybe that will help determine whether the filter performance can be improved.

                      • 8. Re: Can PB can calcute the bounding box as the needed region in AE?
                        chauffeurdevan Level 2

                         

                        Hi,

                        I did a major breakthrough by rethinking the model. Now I get a real speed improvment, and if the image is fully opaque, there is not too much drawback.

                         

                        Instead of a simple bounding box, I'm creating a grid in which each cell represent a region of the source and is float4(1). if there is any non-zero transparent pixel. In the last kernel of the graph, i'm processing only when the corresponding value in the grid is float4(1.). I get really efficient results from that. I'm including two graphs. A basic one with a fixed grid of 16px (I didn't do any beanchmark for the grid size) where I output the original image composited over the scaled grid in green. The second one, where the last kernel is a box blur, the grid size equal the blur radius, and there is a convolution kernel between the grid and the box blur that expand the grid to fit the blur.

                         

                        GridExperience.pbg

                        <?xml version="1.0" encoding="utf-8"?>
                        <graph name = "GridExperience" xmlns="http://ns.adobe.com/PixelBenderGraph/1.0">
                            <metadata name = "namespace" value =  "com.jocelyntremblay"/>
                            <metadata name = "vendor" value = "Jocelyn Tremblay" />
                            <metadata name = "version" type = "int" value = "1" />

                            <!-- Image inputs and outputs of the graph -->
                            <inputImage type = "image4" name = "src" />
                            <outputImage type = "image4" name = "dst" />
                          
                            <!-- Graph parameters -->
                            <parameter type="float2" name="sourceSize" >
                                <metadata name="minValue" type="float2" value="1"/>
                                <metadata name="maxValue" type="float2" value="4096" />
                                <metadata name="defaultValue" type="float2" value="634., 396." />
                                <metadata name="aeUIControl" value="aePoint" />
                                <metadata name="aePointRelativeDefaultValue" type="float2" value="1, 1" />
                            </parameter>
                                <!-- Graph parameters -->
                            <parameter type="float" name="gridSize" >
                                <metadata name="minValue" type="float" value="1"/>
                                <metadata name="maxValue" type="float" value="64" />
                                <metadata name="defaultValue" type="float" value="16" />
                            </parameter>

                             <!-- Embedded kernel -->
                             <kernel>
                              <![CDATA[
                                 <languageVersion : 1.0;>
                                 kernel getProcessingGrid
                                 <  
                                    namespace:"com.jocelyntremblay";
                                    vendor:"Jocelyn Tremblay";
                                    version:1;
                                 >{
                                    input image4 src;
                                    output float4 dst;
                                   
                                    parameter float2 sourceSize
                                    <
                                        parameterType : "inputSize";
                                        inputSizeName : "src";
                                    >;
                                   
                                    parameter float gridSize
                                    <
                                        minValue:float(1.0);
                                        maxValue:float(64.0);
                                        defaultValue:float(5.0);
                                    >;
                                   
                                    region changed(region inputRegion, imageRef inputIndex){
                                        return region(float4(0, 0, ceil(sourceSize.x/gridSize), ceil(sourceSize.y/gridSize)));
                                    }
                                   
                                    void evaluatePixel(){
                                        float j;
                                        float4 pix;
                                        dst = float4(0.0);
                                        for (float i = 0.; i < gridSize; i++){
                                            j = 0.;
                                            for (j; j < gridSize; j++){
                                                pix = sampleNearest(src, float2(floor(outCoord().x) * gridSize + i, floor(outCoord().y) * gridSize + j));
                                                if (pix.a > 0.){
                                                    dst = float4(1.0);
                                                    i = j = gridSize;
                                                }
                                            }
                                           
                                        }
                                    }
                                 }
                              ]]>
                             </kernel>
                             <kernel>
                              <![CDATA[
                                 <languageVersion : 1.0;>
                                 kernel drawProcessingGrid
                                 <  
                                    namespace:"com.jocelyntremblay";
                                    vendor:"Jocelyn Tremblay";
                                    version:1;
                                 >{
                                    input image4 src;
                                    input image4 processingGrid;
                                    output float4 dst;
                                   
                                    parameter float gridSize
                                    <
                                        minValue:float(1.0);
                                        maxValue:float(64.0);
                                        defaultValue:float(5.0);
                                    >;
                                   
                                    void evaluatePixel(){
                                        float4 gridSegment = sampleNearest(processingGrid, float2(floor(outCoord().x/gridSize), floor(outCoord().y/gridSize)));
                                        if (gridSegment.a > 0.){
                                                        //process
                                                        dst = float4(0., 1., 0., 1.);
                                                        float4 tt = sampleNearest(src, outCoord());
                                                        if(tt.a > 0.){
                                                            dst.rgb = tt.rgb;
                                                        }
                                        }
                                        else{
                                            //do not process
                                            dst = float4(0.);
                                        }
                                    }
                                 }
                              ]]>
                             </kernel>

                            <!-- Instances of the nodes -->
                            <node id = "getProcessingGrid" name ="getProcessingGrid" namespace = "com.jocelyntremblay" vendor = "Jocelyn Tremblay" version ="1">
                            <evaluateParameters>
                                    <![CDATA[void evaluateParameters() {
                                        getProcessingGrid::gridSize = gridSize;
                                        getProcessingGrid::sourceSize = sourceSize;
                                    }]]>
                                </evaluateParameters>
                            </node>
                            <node id = "drawProcessingGrid" name ="drawProcessingGrid" namespace = "com.jocelyntremblay" vendor = "Jocelyn Tremblay" version ="1">
                            <evaluateParameters>
                                    <![CDATA[void evaluateParameters() {
                                        drawProcessingGrid::gridSize = gridSize;
                                    }]]>
                                </evaluateParameters>
                            </node>
                           
                            <!-- Connect the graph -->
                            <connect fromImage = "src" toNode = "getProcessingGrid" toInput = "src" />
                            <connect fromImage = "src" toNode = "drawProcessingGrid" toInput = "src" />
                            <connect fromNode = "getProcessingGrid" fromOutput = "dst" toNode = "drawProcessingGrid" toInput = "processingGrid" />
                            <connect fromNode = "drawProcessingGrid" fromOutput = "dst" toImage = "dst" />
                        </graph>

                         

                        GridExperienceBoxBlur.pbg

                        <?xml version="1.0" encoding="utf-8"?>
                        <graph name = "GridExperienceBoxBlur" xmlns="http://ns.adobe.com/PixelBenderGraph/1.0">
                            <metadata name = "namespace" value =  "com.jocelyntremblay"/>
                            <metadata name = "vendor" value = "Jocelyn Tremblay" />
                            <metadata name = "version" type = "int" value = "1" />

                            <!-- Image inputs and outputs of the graph -->
                            <inputImage type = "image4" name = "src" />
                            <outputImage type = "image4" name = "dst" />
                          
                            <!-- Graph parameters -->
                            <parameter type="float2" name="sourceSize" >
                                <metadata name="minValue" type="float2" value="1"/>
                                <metadata name="maxValue" type="float2" value="4096" />
                                <metadata name="defaultValue" type="float2" value="1920., 720." />
                                <metadata name="aeUIControl" value="aePoint" />
                                <metadata name="aePointRelativeDefaultValue" type="float2" value="1, 1" />
                            </parameter>
                           
                            <parameter type="float" name="blurRadius" >
                                <metadata name="minValue" type="float" value="0"/>
                                <metadata name="maxValue" type="float" value="25" />
                                <metadata name="defaultValue" type="float" value="5" />
                            </parameter>

                             <!-- Embedded kernel -->
                             <kernel>
                              <![CDATA[
                                 <languageVersion : 1.0;>
                                 kernel getProcessingGrid
                                 <  
                                    namespace:"com.jocelyntremblay";
                                    vendor:"Jocelyn Tremblay";
                                    version:1;
                                 >{
                                    input image4 src;
                                    output float4 dst;
                                   
                                    parameter float2 sourceSize
                                    <
                                        parameterType : "inputSize";
                                        inputSizeName : "src";
                                    >;
                                    parameter float gridSize
                                    <
                                        minValue:float(1.0);
                                        maxValue:float(64.0);
                                        defaultValue:float(16.0);
                                    >;
                           
                                    region changed(region inputRegion, imageRef inputIndex){
                                        return region(float4(0, 0,  ceil(sourceSize.x/gridSize), ceil(sourceSize.y/gridSize)));
                                    }
                                   
                                    void evaluatePixel(){
                                        float j;
                                        float4 pix;
                                        dst = float4(0.0);
                                        for (float i = 0.; i < gridSize; i++){
                                            j = 0.;
                                            for (j; j < gridSize; j++){
                                                pix = sampleNearest(src, float2(floor(outCoord().x) * gridSize + i, floor(outCoord().y) * gridSize + j));
                                                if (pix.a > 0.){
                                                    dst = float4(1.0);
                                                    i = j = gridSize;
                                                }
                                            }
                                           
                                        }
                                    }
                                 }
                              ]]>
                             </kernel>
                             <kernel>
                              <![CDATA[
                                 <languageVersion : 1.0;>
                                kernel ConvKernel
                                <
                                namespace: "After Effects";
                                vendor : "Adobe Systems Inc.";
                                version : 1;
                                description : "Convolves an image using a smoothing mask";
                                >
                                {
                                    input image4 source;
                                    output pixel4 result;
                                    const float3x3 smooth_mask = float3x3( 1.0, 1.0, 1.0,
                                    1.0, 1.0, 1.0,
                                    1.0, 1.0, 1.0);
                                    const float smooth_divisor = 9.0;
                                   
                                    float4 convolve(float3x3 in_kernel, float divisor) {
                                        float4 conv_result = float4(0.0, 0.0, 0.0, 0.0);
                                        float2 out_coord = outCoord();
                                        for(int i = -1; i <= 1; ++i) {
                                            for(int j = -1; j <= 1; ++j) {
                                                conv_result += sampleNearest(source,
                                                out_coord + float2(i, j)) * in_kernel[i + 1][j + 1];
                                            }
                                        }
                                        conv_result /= divisor;
                                        return conv_result;
                                    }
                                   
                                    void evaluatePixel() {
                                        float4 conv_result = convolve(smooth_mask, smooth_divisor);
                                        result = conv_result;
                                    }
                                   
                                    region needed( region output_region, imageRef input_index ) {
                                        region result = output_region;
                                        result = outset( result, float2( 1.0, 1.0 ) );
                                        return result;
                                    }
                                    region changed( region input_region, imageRef input_index ) {
                                        region result = input_region;
                                        result = outset( result, float2( 1.0, 1.0 ) );
                                        return result;
                                    }
                                } //kernel ends
                                ]]>
                              </kernel>
                              <kernel>
                              <![CDATA[
                                 <languageVersion : 1.0;>
                                    kernel BasicBoxBlur
                                    <   namespace : "AIF";
                                        vendor : "Adobe Systems";
                                        version : 2;
                                        description : "variable Radius Box Blur"; >
                                    {
                                    input image4 src;
                                    input image4 processingGrid;
                                    output float4 dst;
                                   
                                    parameter float blurRadius
                                    <
                                        minValue:float(0.0);
                                        maxValue:float(25.0);
                                        defaultValue:float(5.0);
                                    >;
                                       
                                    dependent int radiusAsInt;
                                    void evaluateDependents(){
                                        radiusAsInt = int(ceil(blurRadius));
                                    }
                                    parameter float gridSize
                                    <
                                        minValue:float(1.0);
                                        maxValue:float(64.0);
                                        defaultValue:float(16.0);
                                    >;
                                   
                                    region needed(region outputRegion, imageRef inputRef){
                                        float2 singlePixel = pixelSize(src);
                                        return outset(outputRegion, float2(singlePixel.x * ceil(blurRadius), singlePixel.y * ceil(blurRadius)));
                                    }
                                    region changed(region inputRegion, imageRef inputRef){
                                        float2 singlePixel = pixelSize(src);
                                        return outset(inputRegion, float2(singlePixel.x * ceil(blurRadius), singlePixel.y * ceil(blurRadius)));
                                    }
                                   
                                    void evaluatePixel(){
                                        float4 gridSegment = sampleNearest(processingGrid, float2(floor(outCoord().x/gridSize), floor(outCoord().y/gridSize)));
                                        if (gridSegment.a > 0.){
                                            float denominator = 0.0;
                                            float4 colorAccumulator = float4(0.0, 0.0, 0.0, 0.0);             
                                            float2 singlePixel = pixelSize(src);
                                            for(int i = -radiusAsInt; i <= radiusAsInt; i++)
                                            {
                                                for(int j = -radiusAsInt; j <= radiusAsInt; j++)
                                                {   
                                                    colorAccumulator += sampleNearest(src,
                                                        outCoord() + float2(float(i) * singlePixel.x, float(j) * singlePixel.y));
                                                    denominator++;
                                                }
                                            }
                                            dst = colorAccumulator / denominator;
                                        }
                                        else{
                                            //do not process
                                            dst = float4(0.);
                                        }
                                    }
                                 }
                              ]]>
                             </kernel>

                            <!-- Instances of the nodes -->
                            <node id = "getProcessingGrid" name ="getProcessingGrid" namespace = "com.jocelyntremblay" vendor = "Jocelyn Tremblay" version ="1">
                            <evaluateParameters>
                                    <![CDATA[void evaluateParameters() {
                                        getProcessingGrid::sourceSize = sourceSize;
                                        getProcessingGrid::gridSize = max(1., blurRadius);
                                    }]]>
                                </evaluateParameters>
                            </node>
                            <node id = "ConvKernel" name ="ConvKernel" namespace = "After Effects" vendor = "Adobe Systems Inc." version ="1"></node>
                            <node id = "BasicBoxBlur" name ="BasicBoxBlur" namespace = "AIF" vendor = "Adobe Systems" version ="2">
                            <evaluateParameters>
                                    <![CDATA[void evaluateParameters() {
                                        BasicBoxBlur::blurRadius = blurRadius;
                                        BasicBoxBlur::gridSize = max(1., blurRadius);
                                    }]]>
                                </evaluateParameters>
                            </node>
                           
                            <!-- Connect the graph -->
                            <connect fromImage = "src" toNode = "getProcessingGrid" toInput = "src" />
                            <connect fromImage = "src" toNode = "BasicBoxBlur" toInput = "src" />
                            <connect fromNode = "getProcessingGrid" fromOutput = "dst" toNode = "ConvKernel" toInput = "source" />
                            <connect fromNode = "ConvKernel" fromOutput = "result" toNode = "BasicBoxBlur" toInput = "processingGrid" />
                            <connect fromNode = "BasicBoxBlur" fromOutput = "dst" toImage = "dst" />
                        </graph>