该程序可以实现图片的模糊处理、灰度处理、二值化处理等功能,和美颜相机比较相似。还可以为图片添加马赛克。
一张图片的形成是由各种颜色的像素块拼在一起所呈现出来的。我们需要列出每个点的像素值,并为其填充相应的颜色。因此,对于一副图像,可以看做其宽w*高h的一个二维数组,即图像=int[w][h],在w和h位置的每个int值,就是这个点的像素值。
图像处理的本质:对代表图像二维数组中的值进行重新计算。
一、点击添加图片按钮,在画布中画出一个圆点
首先,我们先写一个简单的程序,在画布中画一个点。步骤如下:
1.创建一个tuxiang类,利用extends继承JFrame类;
2.编写JFrame中固定程序,使之呈现出一个画布;
3.为画布添加按钮及监听器;
4.创建监听器类,编写按下按钮后所需实现的功能的代码。
代码及结果示例如下:
//1.0 在界面中画出一个点
package TuXiang1;
import java.awt.FlowLayout;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
public class tuxiang1 extends JFrame {
public void initUI(){
this.setSize(450,450);
this.setTitle("图像处理");
this.setDefaultCloseOperation(3);
this.setVisible(true);
FlowLayout fl = new FlowLayout();
this.setLayout(fl);
//加上按钮
JButton buDraw = new JButton("添加图片");
this.add(buDraw);
//加监听器
this.setVisible(true);
//获取画布,一定在界面可见之后
Graphics g = this.getGraphics();
DrawLis1 dl = new DrawLis1(g);
buDraw.addActionListener(dl);
}
public static void main(String[] args) {
tuxiang1 lu=new tuxiang1();
lu.initUI();
}
}
package TuXiang1;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
//画图按钮的监听器,点一下画个东西出来
public class DrawLis1 implements ActionListener{
private Graphics g;
public DrawLis1(Graphics g) {
this.g=g;
}
public void actionPerformed(ActionEvent e) {
System.out.println("dssssss");
g.fillOval(170,160,100,100); //(横坐标,纵坐标,宽,高)
}
}
此程序只实现了在画布中画一个点。如果要添加图片,先在项目文件中存入一张图片,利用监听器,将图片转换成二维数组,一个点一个点的在界面上显示出来。其中用到了java.awt.Color类,可以实现一切数字和颜色之间的转换操作;
二、将图片文件载入图片缓冲区,利用二维数组,将图片画在画布上
主函数tuxiang类不变,在监听器类中实现像素值的存储以及颜色的填充。监听器程序如下:
package TuXiang1;
import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
//画图按钮的监听器,点一下画个图像出来
public class DrawLis2 implements ActionListener{
private Graphics g;
public DrawLis2(Graphics g) {this.g=g;}
public void actionPerformed(ActionEvent e) {
//改为画上一张图片
int[][] ia = getImage();
for(int i=0;i<ia.length;i++) { //下一个像素点的坐标
for(int j=0;j<ia[i].length;j++) { //下一个像素点的坐标
//取得一个int代表当前位置的像素值
int v= ia[i][j];
//如何将这个int值,转变成为color?色即是数
Color color = new Color(v);
//设上这个颜色
g.setColor(color);
g.fillOval(i/2+40, j/2+70, 2, 2);//改变图片显示的坐标 以及像素点的大小
}
}
}
//载入一张图片 将一张图片,转换成二维数组,一个点一个点的在界面上画出
public int[][] getImage(){
java.io.File ff = new File("11.jpg");
//将图片文件载入缓冲图片区
BufferedImage bi = null;
try {
bi = ImageIO.read(ff);//从文件到图片对象
}catch(Exception ef) {
ef.printStackTrace();
}
int w = bi.getWidth();//图片的宽
int h = bi.getHeight();//图片的高
int[][] ia = new int[w][h];//用来装像素点的二维数组
//取得图片中的像素点
for(int i=0;i<w;i++) {
for(int j=0;j<h;j++) {
//取得内存图片中,指定位置的像素值
int iv = bi.getRGB(i, j);//i,j位置的color值
ia[i][j] = iv;//每个像素点的color存入数组
}
}
System.out.println("载入图片成功!");
return ia;
}
}
如上图,在监听器中将图像转换成二维数组即可实现图像的显示;在监听器程序中可以通过改变像素点的大小以及间距(i,j的循环递增值 以及像素点的宽和高),就可以实现图像的模糊处理。 其次,实现图像的二值化,就是利用int创建颜色,将颜色进行拆分后,重新构造一个颜色的填充方式,对图片进行特效处理。
二值化部分代码如下:
Color color = new Color(v);
//二值化
//拆分颜色
int rc = color.getRed();
int rg = color.getGreen();
int rb = color.getBlue();
//重新构造一个颜色
color = new Color(rc,rg,rb);
//改变条件,即可改变颜色的填充范围
if(rc>100) {
g.setColor(Color.red);
}else{
g.setColor(Color.black);
}
二值化效果图:给拆分的颜色添加填充条件 如果将Color的(v)变成(-v)。效果图如下:
灰度图像效果图:取R,G,B三个分量的平均值 单通道图像效果图:仅用R,G,B中某一值 即可:int sum =(rc+rg+rb)/3 ,另外两个置0。color = new Color(rg,0,0); color = new Color(sum,sum,sum);
除此之外,还可以通过添加条件,改变数据等方法,实现图片的去背景、珠纹化、马赛克、黑白、油画等效果。
1.去背景效果。原理是限制颜色填充的区域,只画高于某一值的颜色,即可实现去背景效果
int[][] ia = getImage();
for(int i=0;i<ia.length;i+=1) {
for(int j=0;j<ia[i].length;j+=1) {
int v= ia[i][j]; //取得一个int代表当前位置的像素值
Color color = new Color(v);
//拆分颜色
int rc =color.getRed(); int rg = color.getGreen(); int rb = color.getBlue();
if(rc>120) { //填充颜色条件
g.setColor(color); //设上这个颜色
g.fillOval(i/2+120, j/2+120, 2, 2); //圆形
}}
}
2.珠纹化效果。原理是增加两个像素点之间的距离,改变i,j的自增值,以及像素点的宽高
int[][] ia = getImage();
for(int i=0;i<ia.length;i+=16) {
for(int j=0;j<ia[i].length;j+=16) {
int v= ia[i][j]; //取得一个int代表当前位置的像素值
Color color = new Color(v);
//拆分颜色
int rc =color.getRed(); int rg = color.getGreen(); int rb = color.getBlue();
g.setColor(color); //设上这个颜色
g.fillOval(i/2+40, j/2+70, 8, 8); //圆形
}
}
3.马赛克效果。原理添加随机数,设置像素点的大小随机取值,增加间距。
int[][] ia = getImage();
for(int i=0;i<ia.length;i+=10) {
for(int j=0;j<ia[i].length;j+=10) {
int v= ia[i][j]; //取得一个int代表当前位置的像素值
Color color = new Color(v);
g.setColor(color); //设上这个颜色
//随机数添加马赛克
Random rand = new Random();
int w = rand.nextInt(20);
g.fillRect(i/2+40, j/2+70, w, w); //正方形
}
}
4.黑白效果。原理是设置填充条件,大于某个值填充黑色,否则填充白色。
int rc =color.getRed(); int rg = color.getGreen(); int rb = color.getBlue();
if(rc>120) {
g.setColor(color.BLACK);
}else {
g.setColor(color.WHITE);
}
g.fillOval(i/2+40, j/2+70, 2, 2); //圆形
5.油画效果。原理 填充随机大小的色块
int[][] ia = getImage();
for(int i=0;i<ia.length;i+=5) {
for(int j=0;j<ia[i].length;j+=5) {
int v= ia[i][j]; //取得一个int代表当前位置的像素值Color color = new Color(v);
g.setColor(color);
//随机数添加马赛克
Random rand = new Random();
int w = rand.nextInt(20)+5;
g.fillOval(i/2+40, j/2+70, w, w); //油画}
}
色即是数,数即是色!!! 想要改变图片效果,将图片看作是二维数组,改变数据即可得到想要的效果。
三、在第二版本的基础上,添加菜单栏以及菜单的文件选项,可以在在系统文件夹中选择任意一张照片,显示在画布中
Mune(菜单)是窗体程序最常用的一种组件,在Swing体系中,有两种菜单:
1、基于菜单条的,一般加在JFrame组件上;
2、JpopupMenu:可以其它swing组件是单击右键的弹出式菜单。
创建窗体对象上的菜单条,菜单条上的菜单由三部分组成:
javax.swing.Jmenubar类:放置菜单的菜单条,可以通过new Jmenubar()构造菜单条对象;
javax.swing.JMenu:菜单目录对象,new JMenu("文件"),构造一个菜单条目对象;
javax.swing.JmenuItem:菜单条目录,new JmenuItem(“菜单条目1”)创建;
以上三者关系是:JMenu放在JmenuBar上,JmenuItem放在JMenu上。
如何获取电脑中的文件,实现打开按钮,可以直接百度,别人写好的直接拿来用就可以。
具体实现代码如下:
package TuXiang1;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
public class tuxiang3 extends JFrame {
private DrawLis3 dl = null;
public void initUI(){
this.setSize(600,600);
this.setTitle("图像处理");
this.setDefaultCloseOperation(3);
this.setVisible(true);
FlowLayout fl = new FlowLayout();
this.setLayout(fl);
//加上按钮
JButton buDraw = new JButton("添加图片");
this.add(buDraw);
//加菜单栏
JMenuBar mb = getMB();
this.setJMenuBar(mb);
//加监听器
this.setVisible(true);
//获取画布,一定在界面可见之后
Graphics g = this.getGraphics();
this.dl = new DrawLis3(g);
buDraw.addActionListener(dl);
}
//创建菜单 返回一个菜单条
public JMenuBar getMB(){
JMenuBar mb = new JMenuBar();
//加菜单
JMenu jmFile = new JMenu("文件");
JMenu jmOpp = new JMenu("操作");
mb.add(jmFile);
mb.add(jmOpp);
//给菜单加上菜单项
JMenuItem miOpen = new JMenuItem("打开");
//以匿名内部类的形式,加上监听器
miOpen.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO 自动生成的方法存根
System.out.println("Open..........");
//获取电脑中的文件 看不懂没关系 知道怎么用就可以
JFileChooser chooser = new JFileChooser();
chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
chooser.showDialog(new JLabel(), "选择");
File file = chooser.getSelectedFile();
String fName = file.getAbsoluteFile().toString();
dl.setImageFile(fName);
System.out.println("已选择文件名是" + fName);
}
});
//创建菜单项
JMenuItem miNew = new JMenuItem("新建");
JMenuItem miSave = new JMenuItem("保存");
JMenuItem miExit = new JMenuItem("退出");
//将上述菜单项加到功能菜单上
jmFile.add(miOpen);
jmFile.add(miNew);
jmFile.add(miSave);
jmFile.add(miExit);
return mb;
}
public static void main(String[] args) {
tuxiang3 lu=new tuxiang3();
lu.initUI();
}
}
package TuXiang1;
import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
public class DrawLis3 implements ActionListener{
private Graphics g;
private String imageFileName = null;//要打开的图片文件名
public DrawLis3(Graphics g) {this.g=g;}
public void setImageFile(String sf) {
this.imageFileName = sf;
}
public void actionPerformed(ActionEvent e) {
//改为画上一张图片
int[][] ia = getImage();
for(int i=0;i<ia.length;i++) {
for(int j=0;j<ia[i].length;j++) {
//取得一个int代表当前位置的像素值
int v= ia[i][j];
//如何将这个int值,转变成为color?色即是数
Color color = new Color(v);
//设上这个颜色
g.setColor(color);
g.fillOval(i/2+120, j/2+120, 2, 2);
}
}
}
//载入一张图片 将一张图片,转换成二维数组,一个点一个点的在界面上画出
public int[][] getImage(){
System.out.println("要打开的图片文件名是" + imageFileName);
File ff = new File(imageFileName);
//将图片文件载入缓冲图片区
BufferedImage bi = null;
try {
bi = ImageIO.read(ff);//从文件到图片对象
}catch(Exception ef) {
ef.printStackTrace();
}
int w = bi.getWidth();//图片的宽
int h = bi.getHeight();//图片的高
int[][] ia = new int[w][h];//用来装像素点的二维数组
//取得图片中的像素点
for(int i=0;i<w;i++) {
for(int j=0;j<h;j++) {
//取得内存图片中,指定位置的像素值
int iv = bi.getRGB(i, j);//i,j位置的color值
ia[i][j] = iv;//每个像素点的color存入数组
// System.out.println("getImage 中" +i+" "+j+ "位置像素值是"+iv);
}
}
System.out.println("载入图片成功!");
return ia;
}
}
如上所示,添加了菜单栏,我们就可以选择电脑中任意一张照片。通过改变数据和颜色,就可以对任意一张照片做效果处理。
四、添加滑杆组件,通过滑动滑杆控制图片的大小
滑杆组件为javax.swing.JSlider,通常用来调节颜色、数值;监听器需实现ChangeListener,可获取事件源即拖动的JSlider;在监听器中,得到JSllider拖动时的当前值。
先为界面添加滑杆组件:JSlider js = new JSlider();
package TuXiang1;
import java.awt.FlowLayout;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JSlider;
public class tuxiang5 extends JFrame {
public void initUI(){
this.setSize(600,600);
this.setTitle("图像处理");
this.setDefaultCloseOperation(3);
this.setVisible(true);
FlowLayout fl = new FlowLayout();
this.setLayout(fl);
//加上按钮
JButton buDraw = new JButton("添加图片");
this.add(buDraw);
//滑杆
JSlider js = new JSlider();
this.add(js);
//加监听器
this.setVisible(true);
//获取画布,一定在界面可见之后
Graphics g = this.getGraphics();
DrawLis5 dl = new DrawLis5(g,js);
//加监听器 o.addXXXXListener(接口 k)
js.addChangeListener(dl);
buDraw.addActionListener(dl);
}
public static void main(String args[]) {
tuxiang5 lu=new tuxiang5();
lu.initUI();
}
}
接下来,需要在监听器类中实现滑块的具体功能。如果要用滑块改变图片的大小,需要创建一块内存缓冲区,将图片画在内存缓冲区中。利用接口implements分别实现按钮和滑杆的方法。
package TuXiang1;
import javax.imageio.ImageIO;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
//1.画图按钮的监听器,点一下画个东西出来
//2.拉杆的监听器
public class DrawLis5 implements ActionListener,ChangeListener{
private Graphics g;
private JSlider js;//界面上的拉杆
private int[][] ia;//要初始化的从文件读取的图片数组
public DrawLis5(Graphics g,JSlider js){
this.g=g;
this.js=js;
//装在一张默认的图片
ia = getImage();
}
//当拉杆拉动时,此方法被调用
public void stateChanged(ChangeEvent e){
int v = js.getValue();
System.out.println("js的当前值是"+v);
//记录一下时间
long start = System.currentTimeMillis();
System.out.println("开始时时间是" +start);
//创建一块内存缓冲区,一张内存图片
BufferedImage buffrer = new BufferedImage(500,500,BufferedImage.TYPE_INT_RGB);
Graphics bufferG = buffrer.getGraphics();//缓冲区图片
for(int i=0;i<ia.length;i+=1) { //100
for(int j=0;j<ia[i].length;j+=1) { //100
//取得一个int代表当前位置的像素值
int iv= ia[i][j];
//如何将这个int值,转变成为color?色即是数
Color color = new Color(iv);
//设上这个颜色和画图,都画到内存缓冲区中
bufferG.setColor(color);
//java→os→cpu→内存→总线→显卡→液晶点
bufferG.fillOval(i/v, j/v, 2, 2); //圆形
}
}
//将内存图片,画到界面的画布上
g.drawImage(buffrer,40,70,null);
//记录一下时间
long end = System.currentTimeMillis();
long cost = end - start;
System.out.println("绘制用时:"+(end-start));
}
//当按下按钮时,此方法被调用
public void actionPerformed(ActionEvent e) {
int v = js.getValue();
System.out.println("js的当前值是"+v);
//记录一下时间
long start = System.currentTimeMillis();
System.out.println("开始时时间是" +start);
//创建一块内存缓冲区,一张内存图片
BufferedImage buffrer = new BufferedImage(500,500,BufferedImage.TYPE_INT_RGB);
Graphics bufferG = buffrer.getGraphics();//缓冲区图片
for(int i=0;i<ia.length;i+=1) { //100
for(int j=0;j<ia[i].length;j+=1) { //100
//取得一个int代表当前位置的像素值
int iv= ia[i][j];
//如何将这个int值,转变成为color?色即是数
Color color = new Color(iv);
bufferG.setColor(color);
//java→os→cpu→内存→总线→显卡→液晶点
bufferG.fillOval(i/v, j/v, 2, 2); //圆形
}
}
//将内存图片,画到界面的画布上
g.drawImage(buffrer,40,70,null);
//记录一下时间
long end = System.currentTimeMillis();
long cost = end - start;
System.out.println("绘制用时:"+(end-start));
}
//载入一张图片 将一张图片,转换成二维数组,一个点一个点的在界面上画出
public int[][] getImage(){
java.io.File ff = new File("00.jpg");
//将图片文件载入缓冲图片区
BufferedImage bi = null;
try {
bi = ImageIO.read(ff);//从文件到图片对象
}catch(Exception ef) {
ef.printStackTrace();
}
int w = bi.getWidth();//图片的宽
int h = bi.getHeight();//图片的高
int[][] ia = new int[w][h];//用来装像素点的二维数组
//取得图片中的像素点
for(int i=0;i<w;i++) {
for(int j=0;j<h;j++) {
//取得内存图片中,指定位置的像素值
int iv = bi.getRGB(i, j);//i,j位置的color值
ia[i][j] = iv;//每个像素点的color存入数组
}
}
System.out.println("载入图片成功!");
return ia;
}
}
滑动滑块时,图片的大小会随之变化,同时控制台也会输出当前图片的大小,绘制所用的时间。
五、两张图片叠加效果。存入两张照片,分别填充颜色,可以调节图片的透明度。
监听器类代码:
package TuXiang1;
import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
//画图按钮的监听器,点一下画个东西出来
public class DrawLis6 implements ActionListener{
private Graphics g;
public DrawLis6(Graphics g) {this.g=g;}
public void actionPerformed(ActionEvent e) {
//改为画上一张图片 a,b图叠加效果
int[][] ia = getImage("123.jpg");
int[][] ib = getImage("456.jpg");
for(int i=0;i<ia.length;i++) {
for(int j=0;j<ia[i].length;j++) {
//取得a图片的颜色值
int v= ia[i][j];
Color acolor = new Color(v);
int arc = acolor.getRed();
int arg = acolor.getGreen();
int arb = acolor.getBlue();
//取得b图片的颜色值
v=ib[i][j];
Color bcolor = new Color(v);
int brc = bcolor.getRed();
int brg = bcolor.getGreen();
int brb = bcolor.getBlue();
int lastR = (int)(arc*0.5+brc*0.5);
int lastG = (int)(arg*0.5+brg*0.5);
int lastB = (int)(arb*0.5+brb*0.5);
Color ccc = new Color(lastR,lastG,lastB);
//设上这个颜色
g.setColor(ccc);
g.fillOval(i/3+80, j/3+100, 2, 2);
}
}
}
//载入一张图片 将一张图片,转换成二维数组,一个点一个点的在界面上画出
public int[][] getImage(String fname){
java.io.File ff = new File(fname);
//将图片文件载入缓冲图片区
BufferedImage bi = null;
try {
bi = ImageIO.read(ff);//从文件到图片对象
}catch(Exception ef) {
ef.printStackTrace();
}
int w = bi.getWidth();//图片的宽
int h = bi.getHeight();//图片的高
int[][] ia = new int[w][h];//用来装像素点的二维数组
//取得图片中的像素点
for(int i=0;i<w;i++) {
for(int j=0;j<h;j++) {
//取得内存图片中,指定位置的像素值
int iv = bi.getRGB(i, j);//i,j位置的color值
ia[i][j] = iv;//每个像素点的color存入数组
}
}
System.out.println("载入图片成功!");
return ia;
}
}
改变图片的填充饱和度,即可改变透明度
int lastR = (int)(arc*0.5+brc*0.5);
int lastG = (int)(arg*0.5+brg*0.5);
int lastB = (int)(arb*0.5+brb*0.5);
Color ccc = new Color(lastR,lastG,lastB);