ConvolveOp Filter

ConvolveOp applies a filter to a BufferedImages, to give various efects, as seen in the example below.

Using a ConvolveOp is similar the various other BufferedImageOp classes. In all cases, we can apply a filter to a source to generate a destination. The other BufferedImageOp classes are explained in further detail in these other sections of the notes (AffineTransformOp, ColorConvertOp, LookupOp & RescaleOp).

ConvolveDemo Example (Run Applet)

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;

public class ConvolveDemo extends JApplet
{
    @Override
    public void init()
    {
        this.setContentPane(new View());
    }

    public class View extends JPanel implements ItemListener
    {
        private final float noConvolveMatrix[] =
        {
            0.0f, 0.0f, 0.0f,
            0.0f, 1.0f, 0.0f,
            0.0f, 0.0f, 0.0f
        };
        private final float sharpenMatrix[] =
        {
            -1.0f, -1.0f, -1.0f,
            -1.0f, 9.0f, -1.0f,
            -1.0f, -1.0f, -1.0f
        };          // adds up to 1
        private final float blurMatrix[] =
        {
            0.1111f, 0.1111f, 0.1111f,
            0.1111f, 0.1111f, 0.1111f,
            0.1111f, 0.1111f, 0.1111f
        };   // each element is 1/9
        private final float edgeDetectMatrix[] =
        {
            -0.5f, -0.5f, -0.5f,
            -0.5f, 4.0f, -0.5f,
            -0.5f, -0.5f, -0.5f
        };          // adds up to 0
        private final float lightMatrix[] =
        {
            0.1f, 0.1f, 0.1f,
            0.1f, 1.0f, 0.1f,
            0.1f, 0.1f, 0.1f
        };          // adds to greater than 0
        private final float darkMatrix[] =
        {
            0.01f, 0.01f, 0.01f,
            0.01f, 0.5f, 0.01f,
            0.01f, 0.01f, 0.01f
        };          // adds to less than 0
        private final float convolveMatrices[][] =
        {
            this.noConvolveMatrix, this.sharpenMatrix, this.blurMatrix,
            this.edgeDetectMatrix, this.lightMatrix, this.darkMatrix
        };
        private final String convolveNames[] =
        {
            "Normal", "Sharpen", "Blur",
            "Edge Detection", "Lighten", "Darken"
        };
        private final JComboBox convolveList = new JComboBox(convolveNames);
        private final Image image = new ImageIcon(getClass().getClassLoader().getResource("images/koala.jpg")).getImage();
        private float convolveMatrix[] = this.noConvolveMatrix;  // initialise to have no convolution

        public View()
        {
            super();
            this.add(this.convolveList);
            this.convolveList.addItemListener(this);
        }

        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);


            // place the original file image into a buffered image
            final BufferedImage srcBufferedImg = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
            final Graphics2D SrcG = srcBufferedImg.createGraphics();
            SrcG.drawImage(this.image, 0, 0, getWidth(), getHeight(), this);

            // Do the convolution
            Kernel kernel = new Kernel(3, 3, this.convolveMatrix);
            final ConvolveOp convolve = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
            final BufferedImage destBufferedImg = convolve.filter(srcBufferedImg, null);

            // draw the destination buffered image onto the applet's panel
            g.drawImage(destBufferedImg, 0, 0, getWidth(), getHeight(), this);
        }

        @Override
        public void itemStateChanged(ItemEvent e)
        {
            this.convolveMatrix = this.convolveMatrices[this.convolveList.getSelectedIndex()];
            this.repaint();
        }
    }
}

Blurring a Mirrored Image

We can use the ConvolveOp to blur a mirrored image, to make it more realistic. This is shown in the example below.

Convolve_MirrorImage_Demo Example (Run Applet)

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import javax.swing.*;

public class Convolve_MirrorImage_Demo extends JApplet
{
    @Override
    public void init()
    {
        this.setContentPane(new View());
    }

    public class View extends JPanel
    {
        private final int blurFactor = 20;  // change this value to adjust the amout of bluring
        private final float blurMatrix[] =
        {
            0.1111f, 0.1111f, 0.1111f,
            0.1111f, 0.1111f, 0.1111f,
            0.1111f, 0.1111f, 0.1111f
        };
        private final Image image = new ImageIcon(getClass().getClassLoader().getResource("images/koala.jpg")).getImage();

        public View()
        {
            super();
        }

        @Override
        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);

            // place the original file image into buffered image
            final BufferedImage srcBufferedImg = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
            final Graphics2D SrcG = srcBufferedImg.createGraphics();
            SrcG.drawImage(this.image, 0, 0, getWidth(), getHeight(), this);

            final AffineTransform affineTransform = new AffineTransform();
            affineTransform.translate(0, getHeight());  // need to translate because we are scaling y by a factor of -1
            affineTransform.scale(1.0, -1.0);

            final AffineTransformOp affineTransformOp = new AffineTransformOp(affineTransform, null);
            BufferedImage invertedBufferedImg = affineTransformOp.filter(srcBufferedImg, null);

            // blur the reflected image
            final Kernel kernel = new Kernel(3, 3, this.blurMatrix);
            final ConvolveOp convolve = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
            for (int i = 0; i < this.blurFactor; i++)
            {
                invertedBufferedImg = convolve.filter(invertedBufferedImg, null);
            }

            // draw the original image and the inverted image
            g.drawImage(this.image, 0, 0, getWidth(), getHeight() / 2, this);
            g.drawImage(invertedBufferedImg, 0, getHeight() / 2, getWidth(), getHeight() / 2, this);
        }
    }
}

Blurring and Fading a Mirrored Image

We can use the ConvolveOp to blur a mirrored image and a linear gradient to fade the image, to make it even more realistic. This is shown in the example below.

Convolve_MirrorImageWithFade_Demo Example (Run Applet)

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import javax.swing.*;

public class Convolve_MirrorImageWithFade_Demo extends JApplet
{
    @Override
    public void init()
    {
        this.setContentPane(new View());
    }

    public class View extends JPanel
    {
        private final int blurFactor = 20;  // change this value to adjust the amout of bluring
        private final float blurMatrix[] =
        {
            0.1111f, 0.1111f, 0.1111f,
            0.1111f, 0.1111f, 0.1111f,
            0.1111f, 0.1111f, 0.1111f
        };
        private final Image image = new ImageIcon(getClass().getClassLoader().getResource("images/koala.jpg")).getImage();

        public View()
        {
            super();
        }

        @Override
        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            final Graphics2D g2 = (Graphics2D)g;

            // place the original file image into a buffered image
            final BufferedImage originalBufferedImg = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
            final Graphics2D originalBufferedG = originalBufferedImg.createGraphics();
            originalBufferedG.drawImage(this.image, 0, 0, getWidth(), getHeight(), this);

            // copy and invert the original image to make invertedBufferedImg
            final AffineTransform affineTransform = new AffineTransform();
            affineTransform.translate(0, getHeight());  // need to translate because we are scaling y by a factor of -1
            affineTransform.scale(1.0, -1.0);
            final AffineTransformOp affineTransformOp = new AffineTransformOp(affineTransform, null);
            BufferedImage invertedBufferedImg = affineTransformOp.filter(originalBufferedImg, null);

            // blur invertedBufferedImg
            final Kernel kernel = new Kernel(3, 3, this.blurMatrix);
            final ConvolveOp convolve = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
            for (int i = 0; i < this.blurFactor; i++)
            {
                invertedBufferedImg = convolve.filter(invertedBufferedImg, null);
            }

            // fade the inverted, blurred image
            final BufferedImage fadedBufferedImg = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
            final Graphics2D fadedG = fadedBufferedImg.createGraphics();
            final GradientPaint gradient = new GradientPaint(0, 0, new Color(255, 255, 255, 255), 0, getHeight(), new Color(255, 255, 255, 0));

            fadedG.setPaint(gradient);
            fadedG.fillRect(0, 0, getWidth(), getHeight());
            fadedG.setComposite(AlphaComposite.SrcIn);
            fadedG.drawImage(invertedBufferedImg, 0, 0, getWidth(), getHeight(), this);

            // draw the original image and the fadedImage onto the applet's surface
            g2.drawImage(this.image, 0, 0, getWidth(), getHeight() / 2, this);
            g.drawImage(fadedBufferedImg, 0, getHeight() / 2, getWidth(), getHeight() / 2, this);
        }
    }
}

Blurring A Drop Shadow

We can use the ConvolveOp to blur a shadow. This is shown in the example below.

Convolve_BlurredDropShadow_Demo Example (Run Applet)

import java.awt.*;
import java.awt.image.*;
import javax.swing.*;

public class Convolve_BlurredDropShadow_Demo extends JApplet
{
    @Override
    public void init()
    {
        this.setContentPane(new View());
    }

    public class View extends JPanel
    {
        private final Image image = new ImageIcon(getClass().getClassLoader().getResource("images/koala.jpg")).getImage();
        private final Color shadowColour = Color.black;
        private final Color backgroundColour = Color.white;
        private final int shadowOffset = 15;
        private final int blurFactor = 40;  // the number of times the blur is called. High value is more blurred
        private final int blurFade = 10;  // the width of background used in the blur. High value is smoother
        private final int margin = 5;   // put a border around the image to show up the drop shadow better
        private final float blurMatrix[] =
        {
            0.1111f, 0.1111f, 0.1111f,
            0.1111f, 0.1111f, 0.1111f,
            0.1111f, 0.1111f, 0.1111f
        };

        public View()
        {
            super();

            // put a border around the image to show up the drop shadow better
            this.setBorder(BorderFactory.createLineBorder(this.backgroundColour, this.margin));
        }

        @Override
        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);

            final BufferedImage dropShadowBufferedImg = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
            final Graphics2D dropShadowG = dropShadowBufferedImg.createGraphics();

            // make the drop shadow
            dropShadowG.setColor(Color.yellow);
            dropShadowG.drawImage(this.image, 0, 0, getWidth(), getHeight(), this);
            dropShadowG.setComposite(AlphaComposite.SrcIn);
            dropShadowG.setColor(this.shadowColour);
            dropShadowG.fillRect(0, 0, getWidth(), getHeight());


            BufferedImage blurredBufferedImg = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
            final Graphics2D blurredBufferedG = blurredBufferedImg.createGraphics();

            // blur the shadow into white
            blurredBufferedG.setColor(this.backgroundColour);
            blurredBufferedG.fillRect(0, 0, getWidth(), getHeight());
            blurredBufferedG.drawImage(dropShadowBufferedImg, this.shadowOffset, this.shadowOffset,
                                       getWidth() - this.shadowOffset - this.blurFade, // this.blurFade is needed so that the blur will
                                       getHeight() - this.shadowOffset - this.blurFade, // have some background colour to blur into
                                       this);                                        // the larger the value, the smoother the shadow

            final Kernel kernel = new Kernel(3, 3, this.blurMatrix);
            final ConvolveOp convolve = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
            for (int i = 0; i < this.blurFactor; i++)
            {
                blurredBufferedImg = convolve.filter(blurredBufferedImg, null);
            }

            // draw the blurred drop shadow and then draw the image over it
            g.drawImage(blurredBufferedImg, 0, 0, getWidth(), getHeight(), this);
            g.drawImage(this.image, 0, 0, getWidth() - this.shadowOffset, getHeight() - this.shadowOffset, this);
        }
    }
}
 
<div align="center"><a href="../versionC/index.html" title="DKIT Lecture notes homepage for Derek O&#39; Reilly, Dundalk Institute of Technology (DKIT), Dundalk, County Louth, Ireland. Copyright Derek O&#39; Reilly, DKIT." target="_parent" style='font-size:0;color:white;background-color:white'>&nbsp;</a></div>