灰度处理,二值化,卷积滤镜等基本算法汇总

最近有门《数字图像处理编程实现》的课程。要求写一个对图像处理的小程序,包括对图像的灰度处理,二值化处理等等。于是花了三天时间,看了写书也在网上找了些资料,基本完成了作业要求。现将我做的小程序记录下来,一方面做个备份,另一方面拿出来给大家分享,也请大家指正。


一.程序的主窗口


package person.hongqiang.ImageProcessing;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;


public class ImageProcessing extends JFrame implements ActionListener {
    private ImageIcon icon =null;
    private String name;

    //创建菜单数组
     JMenu[] jm = {new JMenu("文件"), new JMenu("操作"), new JMenu("卷积滤镜")};
    //创建普通菜单项数组
     JMenuItem[] jmi = new JMenuItem[]{new JMenuItem("打开"), new JMenuItem("保存"), 
            new JMenuItem("灰度处理"), new JMenuItem("RGB色彩通道过滤"), new JMenuItem("二值化"),new JMenuItem("加强边缘"),
            new JMenuItem("锐化"), new JMenuItem("模糊"), new JMenuItem("浮雕")};
    //创建菜单栏
     JMenuBar jmb = new JMenuBar();

     JLabel jl1 = new JLabel();
     JScrollPane jlf = new JScrollPane(jl1);
    //创建显示源图像的标签
    JLabel jls = new JLabel();
    //将显示源图像的标签放在滚动窗格中
     JScrollPane jspz = new JScrollPane(jls);
    //创建显示目标图像的标签
     JLabel jlt = new JLabel();
    //将显示目标图像的标签放在滚动窗格中
     JScrollPane jspy = new JScrollPane(jlt);
    //创建显示文字标签
     JLabel jl = new JLabel("涛哥带你学编程");
    //创建面板
    JPanel jp = new JPanel();
    String[] str = {"加强边缘","锐化","模糊","浮雕"};


    //构造器
    public ImageProcessing(){
        //将文件菜单添加进菜单栏
        jmb.add(jm[0]);
        //将打开,保存菜单项添加进文件菜单,并注册监听器
        for (int i = 0; i < 2; i++){
            jm[0].add(jmi[i]);
            jmi[i].addActionListener(this);
        }
        //将操作菜单添加进菜单栏
        jmb.add(jm[1]);
        //将灰度处理,RGB色彩通道过滤添加进操作菜单,并注册监听器
        for (int i = 2; i < 5; i++){
            jm[1].add(jmi[i]);
            jmi[i].addActionListener(this);
        }
        //将卷积菜单添加进菜单栏
        jmb.add(jm[2]);
        //将加强边缘,锐化,模糊,浮雕添加进卷积滤镜菜单,并注册监听器
                for (int i = 5; i < jmi.length; i++){
                    jm[2].add(jmi[i]);
                    jmi[i].addActionListener(this);
                }
        //将二值化菜单添加进菜单栏
        //jmb.add(jm[3]);
        //jm[3].addActionListener(this);
        //将菜单栏添加进窗体
        this.setJMenuBar(jmb);
        //将带有滚动条的文本区添加进窗体
        this.add(jlf);
        //将标签添加进面板
        jp.add(jl);
        this.add(jp, BorderLayout.SOUTH);

        //设置窗口的关闭动作,标题,大小,位置,以及可见性
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("图像处理编程");
        this.setBounds(400, 300, 700, 500);
        this.setVisible(true);

    }


    public static void main(String[] args) throws IOException{
        // TODO Auto-generated method stub
       new ImageProcessing();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
        //二值化处理,并将处理后的图片保存
        if (e.getSource() == jmi[4]){
            BinaryProcessing bp = new BinaryProcessing(icon);
            try {
                ImageIO.write(bp.getBuf(), "jpg", new File(System.getProperty("user.dir")+"/src/images/"+name+"_bp.jpg"));
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }
        //选中打开菜单项
        else if (e.getSource() == jmi[0]){
            OpenPicture op = new OpenPicture(this,jl1);
            icon = op.getImageIcon();
            name = op.getImageName();

        }
        //选中保存菜单栏
        else if (e.getSource() == jmi[1]){
            //jta.append("保存文件");
        }
        //选中灰度处理菜单栏,并将处理后的图片保存
        else if (e.getSource() == jmi[2]){
            GrayProcessing gp = new GrayProcessing(icon);
            try {
                ImageIO.write(gp.getBuf(), "jpg", new File(System.getProperty("user.dir")+"/src/images/"+name+"_gp.jpg"));
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }
        //选中RGB色彩通道过滤,并将处理后的图片保存
        else if (e.getSource() == jmi[3]){
            RGBFilter rgbf = new RGBFilter(icon);
            try {
                ImageIO.write(rgbf.getBuf(), "jpg", new File(System.getProperty("user.dir")+"/src/images/"+name+"_rgbf.jpg"));
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }

        //选中卷积滤镜
        else{
            for (int i = 5; i < jmi.length; i++){
                if (e.getSource() == jmi[i]){
                ConvolveFilter cf = new ConvolveFilter(jmi[i],icon,i);
                try {
                    ImageIO.write(cf.getBuf(), "jpg", new File(System.getProperty("user.dir")+"/src/images/"+name+"_cf_"+str[i-5]+".jpg"));
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
                }
            }
        }
    }

}

效果图:

这部分主要做了一个简单的主窗体。接下来是打开一个图片,然后对图片进行各种处理。接着往下看:


二.打开一张图片


package person.hongqiang.ImageProcessing;

import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class OpenPicture {
    private ImageIcon icon;
    private String name;

    public OpenPicture(JFrame jf, JLabel jl){
        //创建文件选择器
        JFileChooser jfc = new JFileChooser(); 
        //弹出文件选择器
        jfc.showDialog(jf, "请选择要打开的图片");
        //获取图片文件路径
        String path = jfc.getSelectedFile().getAbsolutePath();
        //获取文件名字,不带后缀
        String Imagename = jfc.getSelectedFile().getName();
        String prefix = Imagename.substring(Imagename.lastIndexOf("."));
        int num = prefix.length();                                            //得到后缀名长度
        name = Imagename.substring(0, Imagename.length()-num);                         //得到不带后缀的文件名
        //创建图标对象
         icon = new ImageIcon(path);
        //将图标对象加入标签
        jl.setIcon(icon);
        //设置源图像标签的水平,垂直对齐方式为居中
        jl.setVerticalAlignment(JLabel.CENTER);
        jl.setHorizontalAlignment(JLabel.CENTER);
    }

    public ImageIcon getImageIcon(){
        return icon;
    }

    public String getImageName(){
        return name;
    }
}

该程序通过创建文件选择器,在弹出的文件选择器中选择需要处理的图像,然后把选中的图片显示在主窗口中。

效果图如下:


三.灰度处理


基本原理:
彩色图像中的每个像素的颜色有R,G,B三个分量决定,而每个分量有255种值可取,这样一个像素点可以有1600多万(255*255*255)的颜色变化范围。而灰度图像是R,G,B三个分量相同的一种特殊的彩色图像,其一个像素点的变化为255种。灰度图像的描述与彩色图像一样仍然反映了整幅图像的整体和局部的色度和亮度等级的分布和特征。所以在数字图像处理中一般先将各种格式的图像转变为灰度图像以使后续的图像的计算量变少点。

实现方法:

  1. 求出每个像素点的R,G,B三个分量的平均值,然后将这个平均值赋予这个像素的三个分量
  2. 根据YUV的颜色空间中,Y的分量的物理意义是点的亮度,由该值反映亮度等级,根据RGB和YUV颜色空间的变化关系可建立亮度Y与R,G,B三个颜色分量的对应关系:Y=0.3R+0.59G+0.11B,以这个亮度值表达图像的灰度值。

本程序中实现图像灰度处理的方法是:通过Java类库中提供的ColorConvertOp类,创建了一个以sRGB为源色彩空间,以线性灰度色彩空间为目标色彩空间的ColorConvertOp对象。创建ColorConvertOp对象后,就可以调用ColorConvertOp对象的filter方法对图像进行色彩空间转换了。

//创建用来进行灰度处理的ColorConvertOp对象
            ColorConvertOp cco = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB),
                    ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
            //进行灰度处理
            cco.filter(sourceBuf, targetBuf);

完整代码如下:

package person.hongqiang.ImageProcessing;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;

public class GrayProcessing extends JFrame {
    public int width;
    public int height;
    private ImageIcon ii = null;

     //创建显示源图像的标签,并将其放在滚动窗格中
    JLabel jls = new JLabel();
    JScrollPane jspz = new JScrollPane(jls);
    //创建显示目标图像的标签,并将其放在滚动窗格中
    JLabel jlt = new JLabel();
    JScrollPane jspy = new JScrollPane(jlt);
    //创建分割窗格,并设置各子窗格中显示的控件
    JSplitPane jsp = new JSplitPane (JSplitPane.HORIZONTAL_SPLIT,jspz,jspy);

    public BufferedImage getBuf(){
        BufferedImage targetBuf1 = new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);
        //获取表示源图像的BufferedImage对象的画笔
        Graphics g = targetBuf1.getGraphics();
        //将待处理的图像绘制到源图像的BufferedImage对象中
        g.drawImage(ii.getImage(), 0, 0, Color.white,null);
        return targetBuf1;

    }

    //构造器
    public GrayProcessing(ImageIcon icon){
        ii = icon;
        //将图片设置到源标签中
        jls.setIcon(ii);
        //设置源图像标签的水平,垂直对齐方式为居中
        jls.setVerticalAlignment(JLabel.CENTER);
        jls.setHorizontalAlignment(JLabel.CENTER);
        //设置目标图像标签的水平,垂直对齐方式为居中
        jlt.setVerticalAlignment(JLabel.CENTER);
        jlt.setHorizontalAlignment(JLabel.CENTER);
        //获取处理后的图像对应的图标
        ii =this.processGrayImage(ii.getImage());
        //将处理后的图片设置到目标标签中
        jlt.setIcon(ii);
        //设置分割条的初始位置
        jsp.setDividerLocation(350);
        //设置分割条的宽度
        jsp.setDividerSize(4);
        //将分割条添加到窗体
        this.add(jsp);
        //设置窗体的标题,大小,位置以及可见性
        this.setTitle("灰度处理结果");
        this.setBounds(450,350,700,500);
        this.setVisible(true);
        //设置窗体关闭动作
        this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
    }

    //对图片进行灰度处理的方法
        public ImageIcon processGrayImage (Image source){
            //获取图像的宽度和高度
            width = source.getWidth(null);
            height = source.getHeight(null);
            //创建表示源图像的BufferedImage对象
            BufferedImage sourceBuf = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
            //创建表示处理后目标图像的BufferedImage对象
            BufferedImage targetBuf = new BufferedImage(width,height,BufferedImage.TYPE_USHORT_GRAY);
            //获取表示源图像的BufferedImage对象的画笔
            Graphics g = sourceBuf.getGraphics();
            //将待处理的图像绘制到源图像的BufferedImage对象中
            g.drawImage(source, 0, 0, Color.white,null);
            //创建用来进行灰度处理的ColorConvertOp对象
            ColorConvertOp cco = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB),
                    ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
            //进行灰度处理
            cco.filter(sourceBuf, targetBuf);
            //返回处理后图像对应的图标对象
            return new ImageIcon(targetBuf);
        }
}

效果图如下:


四.RGB色彩通道过滤


基本原理:
RGB色彩模式中每一个像素使用一个32位的整数来表示颜色,在这32位中,其中分别使用8位来表示红(R),绿(G),蓝(B)三个色彩通道,还有8位用来表示像素透明度。因此在对各个色彩通道进行处理的时候,需先将各个通道的值取出来,然后再进行处理,最后再组装成一个整的32位的颜色值。本程序是通过改变三个色彩通道的值来改变每个像素点的颜色值。

完整代码如下:

package person.hongqiang.ImageProcessing;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.FilteredImageSource;
import java.awt.image.RGBImageFilter;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JSplitPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class RGBFilter extends JFrame implements ChangeListener {
    //获取源图片图标对象
    //private ImageIcon icon =null;
    ImageIcon ii = null;
     //创建显示源图像的标签,并将其放在滚动窗格中
    JLabel jls = new JLabel();
    JScrollPane jspz = new JScrollPane(jls);
    //创建显示目标图像的标签,并将其放在滚动窗格中
    JLabel jlt = new JLabel();
    JScrollPane jspy = new JScrollPane(jlt);
    //创建分割窗格,并设置各子窗格中显示的控件
    JSplitPane jsp = new JSplitPane (JSplitPane.HORIZONTAL_SPLIT,jspz,jspy);
    //创建表示通道的标签数组
    JLabel[] jl = {new JLabel("红色"),
                           new JLabel("绿色"),
                           new JLabel("蓝色")
    };
    //创建三个用来控制各通道颜色分量的滑块
    JSlider[] js = {new JSlider(-255,255),
                             new JSlider(-255,255),
                             new JSlider(-255,255)
    };
    //创建一个面板
    JPanel jp = new JPanel();
    //创建自定义的过滤器对象
    MyColorFilter mcf = new MyColorFilter(js[0].getValue(), js[1].getValue(), js[2].getValue());

    public BufferedImage getBuf(){
        int width = ii.getImage().getWidth(null);
        int height = ii.getImage().getHeight(null);
        BufferedImage targetBuf1 = new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);
        //获取表示源图像的BufferedImage对象的画笔
        Graphics g = targetBuf1.getGraphics();
        //将待处理的图像绘制到源图像的BufferedImage对象中
        g.drawImage(ii.getImage(), 0, 0, Color.white,null);
        return targetBuf1;

    }

    //构造器
    public RGBFilter(ImageIcon icon){

        jls.setIcon(icon);
        jls.setVerticalAlignment(JLabel.CENTER);
        jls.setHorizontalAlignment(JLabel.CENTER);
        jlt.setVerticalAlignment(JLabel.CENTER);
        jlt.setHorizontalAlignment(JLabel.CENTER);
        //将处理后的图片设置到目标标签中
         ii = icon;
        jlt.setIcon(ii);
        jsp.setDividerLocation(500);
        jsp.setDividerSize(4);
        this.add(jsp, BorderLayout.CENTER);
        //将标签以及滑块添加道面板中,并为滑块注册监听器
        for (int i = 0; i < js.length; i++){
            jp.add(jl[i]);
            jp.add(js[i]);
            js[i].addChangeListener(this);
    }
        //将面板添加进窗体
        this.add(jp,BorderLayout.SOUTH);
        //设置窗体的标题,大小,位置以及可见性
        this.setTitle("RGB滤波");
        this.setBounds(300,300,1000,500);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);


        }

    @Override
    public void stateChanged(ChangeEvent e) {
        // TODO Auto-generated method stub
        //设置三个分量的值
        mcf.setRGBValue(js[0].getValue(),js[1].getValue(),js[2].getValue());
        //获取过滤后的图像显示到目标标签中
        Image tempImg = createImage(new FilteredImageSource(ii.getImage().getSource(),mcf));
        jlt.setIcon(new ImageIcon(tempImg));
    }   

    }

//自定义的RGB色彩通道过滤器类
        class MyColorFilter extends RGBImageFilter{
            //RGB色彩通道各自的调整值
            int rc,gc,bc;
            public MyColorFilter(int rc, int gc, int bc){
                this.rc = rc;
                this.gc = gc;
                this.bc = bc;
            }

            //设置各个色彩通道的调整值
            public void setRGBValue(int rc, int gc, int bc){
                this.rc = rc;
                this.gc = gc;
                this.bc = bc;
            }

            @Override
            public int filterRGB(int x, int y, int rgb) {
                // TODO Auto-generated method stub
                //取出红色通道中的数值
                int tempRed = (rgb&0x00ff0000) >> 16;
                //对红色通道值进行处理
                tempRed += rc;
                //判断处理后的数值是否越位
                tempRed = (tempRed < 255) ? ((tempRed > 0) ? tempRed : 0) : 255;
                //将处理后的值移回指定位
                tempRed = tempRed << 16;

                //取出绿色通道中的数值
                int tempGreen = (rgb&0x0000ff00) >> 8;
                //对绿色通道值进行处理
                tempGreen += gc;
                //判断处理后的数值是否越位
                tempGreen = (tempGreen < 255) ? ((tempGreen > 0) ? tempGreen : 0) : 255;
                //将处理后的值移回指定位
                tempGreen = tempGreen << 8;

                //取出蓝色通道中的数值
                int tempBlue = (rgb&0x000000ff);
                //对蓝色通道值进行处理
                tempBlue += bc;
                //判断处理后的数值是否越位
                tempBlue = (tempBlue < 255) ? ((tempBlue > 0) ? tempBlue : 0) : 255;
                //将红,绿,蓝三色通道的值与颜色本身中高8位用来控制透明度的值进行按位或运算并返回
                return (rgb&0xff000000) | tempRed |tempGreen | tempBlue;
            }

}

效果图如下:

图片下方的三个滑块对应R,G,B三个色彩空间,通过控制三个滑块的值来调节图片的颜色。(有点美图秀秀的感觉)


五.二值化处理


基本原理:
图像的二值化,就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的只有黑和白的视觉效果。

本程序的二值化算法为:

  1. 首先获取每个像素点的灰度值,目前使用简单的(R+G+B)/3
  2. 选定一个阈值
  3. 将一个像素点灰度值和它周围的8个灰度值相加再除以9,然后和阈值进行比较。大于阈值则置为255,小于阈值则置为0
  4. 由于每张图像的最佳阈值是不一样的,所以在本程序中,阈值是不固定的,可以通过滑块为不同的图像找到合适的阈值

代码如下:

package person.hongqiang.ImageProcessing;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JSplitPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * 具体二值花算法:
 * 1.首先获取每个像素点的灰度值。目前使用简单的(R+G+B)/3
 * 2.然后选定一个阈值
 * 3.将一个像素点灰度值和它周围的8个灰度值相加再除以9,然后和阈值比较。大于阈值则置为255,小于则置为0
 * @author hadoop002
 *
 */
public class BinaryProcessing extends JFrame implements ChangeListener {

    private BufferedImage targetBuf;
    //选定一个阈值
    private int sw;
    private ImageIcon icon;
    //创建显示源图像的标签,并将其放在滚动窗格中
    JLabel jls = new JLabel();
    JScrollPane jspz = new JScrollPane(jls);
    //创建显示目标图像的标签,并将其放在滚动窗格中
    JLabel jlt = new JLabel();
    JScrollPane jspy = new JScrollPane(jlt);
    //创建分割窗格,并设置各子窗格中显示的控件
    JSplitPane jsp = new JSplitPane (JSplitPane.HORIZONTAL_SPLIT,jspz,jspy);
    //创建一个面板
    JPanel jp = new JPanel();
    //创建阈值标签
    JLabel jl = new JLabel("阈值");
    //创建用来控制阈值的滑块
    JSlider js = new JSlider(0, 255);


    public BufferedImage getBuf(){
        return targetBuf;
    }

    public BinaryProcessing(ImageIcon ii){

        icon = ii;
        sw = 78;

        //获取待处理图像的宽度何高度
        int width = icon.getImage().getWidth(null);
        int height = icon.getImage().getHeight(null);

        //创建一个BufferedImage对象,分别用来放置待处理图像
        BufferedImage sourceBuf = new BufferedImage (width,height,BufferedImage.TYPE_INT_ARGB);
        targetBuf = new BufferedImage (width,height,BufferedImage.TYPE_BYTE_BINARY);
        //将待处理的图像放入BufferedImage对象中
        Graphics g = sourceBuf.getGraphics();
        g.drawImage (icon.getImage(), 0, 0, Color.white, null);
        //获取指定坐标的ARGB的像素值
        //int rgb = sourceBuf.getRGB(0,0);
        //定义每个像素点的灰度值
        int [][] gray = new int[width][height];

        for (int x = 0; x < width; x++){
            for (int y = 0; y < height; y++){
                gray[x][y] = getGray(sourceBuf.getRGB(x, y));
            }
        }


        for (int x = 0; x < width; x++){
            for (int y = 0; y < height; y++){
                if (getAverageColor(gray,x,y,width,height) > sw){
                    int max = new Color(255,255,255).getRGB();
                    targetBuf.setRGB(x, y, max);
                }else{
                    int min = new Color(0,0,0).getRGB();
                    targetBuf.setRGB(x, y, min);
                }
            }
        }

        jls.setIcon(icon);
        jls.setVerticalAlignment(JLabel.CENTER);
        jls.setHorizontalAlignment(JLabel.CENTER);
        jlt.setVerticalAlignment(JLabel.CENTER);
        jlt.setHorizontalAlignment(JLabel.CENTER);
        //获取处理后的图像并设置到目标标签中
        jlt.setIcon(new ImageIcon(targetBuf));
        //设置分割条的初始位置
        jsp.setDividerLocation(400);
        //设置分割条的宽度
        jsp.setDividerSize(4);
        this.add(jsp);
        //将标签和滑块添加进面板中,并为滑块注册监听器
        jp.add(jl);
        jp.add(js);
        js.addChangeListener(this);
        //将面板添加进窗体
        this.add(jp,BorderLayout.SOUTH);

        this.setTitle("二值化处理");
        this.setBounds(500, 400, 800, 500);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    }

    public static int getGray(int rgb){
        String str = Integer.toHexString(rgb);
        int r = Integer.parseInt(str.substring(2, 4), 16);
        int g = Integer.parseInt(str.substring(4, 6), 16);
        int b = Integer.parseInt(str.substring(6, 8), 16);
        //或者直接new一个color对象
        Color c = new Color(rgb);
        r = c.getRed();
        g = c.getGreen();
        b = c.getBlue();
        int top = (r + g + b) / 3;
        return (int)(top);
    }

    public static int getAverageColor (int[][] gray, int x, int y, int w, int h){
        int rs = gray[x][y]
                                     + (x == 0 ? 255 :gray[x - 1][y])
                                     + (x == 0 || y == 0 ? 255 : gray[x - 1][y - 1])
                                     + (x == 0 || y == h - 1 ? 255 : gray[x - 1][y + 1])
                                     + (y == 0 ? 255 : gray[x][y - 1])
                                     + (y == h - 1 ? 255 : gray[x][y + 1])
                                     + (x == w - 1 ? 255 : gray[x + 1][y])
                                     + (x == w - 1 || y == 0 ? 255 : gray[x + 1][y-1])
                                     + (x == w - 1 || y ==h - 1 ? 255 : gray[x + 1][y + 1]);
        return rs / 9;
    }

    @Override
    public void stateChanged(ChangeEvent e) {
        // TODO Auto-generated method stub
        //获取待处理图像的宽度何高度
                int width = icon.getImage().getWidth(null);
                int height = icon.getImage().getHeight(null);

                //创建一个BufferedImage对象,分别用来放置待处理图像
                BufferedImage sourceBuf = new BufferedImage (width,height,BufferedImage.TYPE_INT_ARGB);
                targetBuf = new BufferedImage (width,height,BufferedImage.TYPE_BYTE_BINARY);
                //将待处理的图像放入BufferedImage对象中
                Graphics g = sourceBuf.getGraphics();
                g.drawImage (icon.getImage(), 0, 0, Color.white, null);
                //获取指定坐标的ARGB的像素值
                //int rgb = sourceBuf.getRGB(0,0);
                //定义每个像素点的灰度值
                int [][] gray = new int[width][height];

                for (int x = 0; x < width; x++){
                    for (int y = 0; y < height; y++){
                        gray[x][y] = getGray(sourceBuf.getRGB(x, y));
                    }
                }

                sw = js.getValue();

                for (int x = 0; x < width; x++){
                    for (int y = 0; y < height; y++){
                        if (getAverageColor(gray,x,y,width,height) > sw){
                            int max = new Color(255,255,255).getRGB();
                            targetBuf.setRGB(x, y, max);
                        }else{
                            int min = new Color(0,0,0).getRGB();
                            targetBuf.setRGB(x, y, min);
                        }
                    }
                }

                //获取处理后的图像并设置到目标标签中
                jlt.setIcon(new ImageIcon(targetBuf));
    }
}

效果图如下:


滑动图像下方滑块,调节阈值,找到适合图像的阈值


六.卷积滤镜(加强边缘,锐化,模糊,浮雕)


基本原理:
当需要对图像进行特殊处理(例如浮雕,锐化,模糊等)时,需要使用卷积变换。卷积变换的核心是变换矩阵,该矩阵是根据相邻几个像素计算出处理后像素的颜色。例如,当卷积矩阵为3x3时,当要计算目标图像[x,y]点像素颜色值时,需要把卷积矩阵的中心元素与目标图像中的[x,y]处的像素点对齐,然后把卷积矩阵中的元素与对应的像素依次相乘,最后九个乘积再求和就得到[x,y]像素点处理后的颜色值。

完整代码如下:

package person.hongqiang.ImageProcessing;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;

public class ConvolveFilter extends JFrame {
    private ImageIcon ii;

    //创建显示源图像的标签,并将其放在滚动窗格中
        JLabel jls = new JLabel();
        JScrollPane jspz = new JScrollPane(jls);
        //创建显示目标图像的标签,并将其放在滚动窗格中
        JLabel jlt = new JLabel();
        JScrollPane jspy = new JScrollPane(jlt);
        //创建分割窗格,并设置各子窗格中显示的控件
        JSplitPane jsp = new JSplitPane (JSplitPane.HORIZONTAL_SPLIT,jspz,jspy);

        public BufferedImage getBuf(){
            int width = ii.getImage().getWidth(null);
            int height = ii.getImage().getHeight(null);
            BufferedImage targetBuf1 = new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);
            //获取表示源图像的BufferedImage对象的画笔
            Graphics g = targetBuf1.getGraphics();
            //将待处理的图像绘制到源图像的BufferedImage对象中
            g.drawImage(ii.getImage(), 0, 0, Color.white,null);
            return targetBuf1;

        }

    public ConvolveFilter(JMenuItem jmi, ImageIcon icon, int i){
        //创建表示不同滤镜的卷积矩阵
        float[][] data = {
            //加强边缘
                {0f, -1f, 0f,
                 -1f, 5f, -1f,
                 0f, -1f, 0f
                 },
            //锐化
                {-0.125f, -0.125f, -0.125f,
                 -0.125f, 2f, -0.125f,
                 -0.125f, -0.125f, -0.125f
                },
            //模糊
                {0.09375f, 0.09375f, 0.09375f,
                 0.09375f, 0.25f, 0.09375f,
                 0.09375f, 0.9375f, 0.09375f
                },
            //浮雕
                {2f, 0f, 2f,
                 0f, 0f, 0f,
                 2f, 0f, -5
                }
        };
        String [] title = {"加强边缘处理结果", "锐化结果", "模糊处理结果", "浮雕处理结果"};
        //获取待处理图像的宽度何高度
        int width = icon.getImage().getWidth(null);
        int height = icon.getImage().getHeight(null);
        //创建两个BufferedImage对象,分别用来放置待处理图像于处理后的图像
        BufferedImage sourceBuf = new BufferedImage (width,height,BufferedImage.TYPE_INT_ARGB);
        BufferedImage targetBuf = new BufferedImage (width,height,BufferedImage.TYPE_INT_ARGB);
        //将待处理图像绘制加载到源BufferedImage对象中
        ii = icon;
        Graphics g = sourceBuf.getGraphics();
        g.drawImage (ii.getImage(), 0, 0, Color.white, null);
        //创建封装卷积矩阵的Kernel对象
        Kernel kernel = new Kernel(3, 3, data[i-5]);
        ConvolveOp co = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP,null);
        co.filter(sourceBuf, targetBuf);
        ii = new ImageIcon(targetBuf);
        //获取处理后的图像并设置到目标标签中
        jlt.setIcon(new ImageIcon(targetBuf));
        jlt.setVerticalAlignment(JLabel.CENTER);
        jlt.setHorizontalAlignment(JLabel.CENTER);
        jls.setIcon(icon);
        jls.setVerticalAlignment(JLabel.CENTER);
        jls.setHorizontalAlignment(JLabel.CENTER);
        //设置分割条的初始位置
        jsp.setDividerLocation(400);
        //设置分割条的宽度
        jsp.setDividerSize(4);
        this.add(jsp);
        this.setTitle(title[i-5]);
        this.setBounds(500, 400, 800, 500);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    }

}

效果图如下:

  • 加强边缘

  • 锐化

  • 模糊

  • 浮雕


至此,整个程序的基本功能介绍完毕。处理后的图片都保存在程序中指定的位置(代码中有)。效果如下:


备注:此项目的源代码可以去我的资源库下载


  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值