图片有许多种滤镜效果,那如何在不更改代码的情况下,通过点击窗体上的按钮将自己想要的滤镜效果绘制在窗体上呢?很简单,即通过安装监听器,实现每个按钮都能动作监听。这需要我们创建三个类——图片处理界面类、图片按钮选择监听器类、图片处理效果类。
图片处理界面类
-创建一个初始化界面
public void init() {
JFrame jf=new JFrame();
jf.setTitle("图形图像处理");
jf.setSize(800,800);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setLocationRelativeTo(null);//窗体位置居中
//设置布局
FlowLayout flow=new FlowLayout();
jf.setLayout(flow);
jf.setVisible(true);//添加组件后可视化
}
-添加监听器 创建监听器对象
-获取Graphics(绘图类) 传入监听器中
imglisten.g=jf.getGraphics();
- 创建函数方法,批量循环完成多个按钮的创建、添加与监听器加载,减少代码重用
public void addButton() {
String[] btnstrs= {"原图","反片","脸部提亮","马赛克","美白","轮廓提取","灰度","二值化","油画","图片融合","撤回"};//定义一个字符串数组 存储所有按钮的字符串
for(int i=0;i<btnstrs.length;i++) {
String btnstr=btnstrs[i];
//窗体添加按钮
JButton btn=new JButton(btnstr);
this.add(btn);
//按钮添加监听器对象
btn.addActionListener(imglisten);
}
}
完整代码:
import java.awt.*;
import javax.swing.*;
public class Imagepad extends JFrame {
private static final long serialVersionUID = 1L;
//创建监听器对象
ImageListener imglisten=new ImageListener();
public void init() {
this.setTitle("图形图像处理");
this.setSize(800,800);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);//窗体位置居中
//设置布局
FlowLayout flow=new FlowLayout();
setLayout(flow);
addButton();//调用函数
//获取Graphics对象 传给监听器中的Gaphics 类型属性变量名
this.setVisible(true);//添加组件后可视化
imglisten.g=this.getGraphics();//在可视化之后,在窗体上获取,赋值给监听器对象
}
/**
* 创建函数方法
* 批量循环完成多个按钮的创建、添加与监听器加载,减少代码重用
*/
public void addButton() {
String[] btnstrs= {"原图","反片","脸部提亮","马赛克","美白","轮廓提取","灰度","二值化","油画","图片融合","撤回"};//定义一个字符串数组 存储所有按钮的字符串
for(int i=0;i<btnstrs.length;i++) {
String btnstr=btnstrs[i];
//窗体添加按钮
JButton btn=new JButton(btnstr);
this.add(btn);
//按钮添加监听器对象
btn.addActionListener(imglisten);
}
}
public static void main(String[]args) {
Imagepad imagepad=new Imagepad();
imagepad.init();
}
}
图片按钮选择监听器类
-实现动作监听器 implements ActionListener
-创建图片处理效果类对象
-创建ImageListener(){}方法,定义图片路径,得到图片的二维数组
public ImageListener() {
//定义给定图片的路径
String imgpath01="C:\\Users\\31491\\Pictures\\toux.jpg";
String imgpath02="C:\\Users\\31491\\Pictures\\ziji1.jpg";
String imgpath03="C:\\Users\\31491\\Pictures\\ziji2.jpg";
String imgpath04="C:\\Users\\31491\\Pictures\\bear.jpg";
//数组初始化
imgarr=imgeff.getimagepixelarry(imgpath01);
imgarr1 = imgeff.getimagepixelarry(imgpath01);
imgarr2=imgeff.getimagepixelarry(imgpath04);
}
- 重写监听器的方法 actionPerformed(ActionEvent e){}
- 在方法中可以获取按钮上的字符串
- 通过字符串 选择使用哪种滤镜来绘制图片
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ImageListener implements ActionListener {
Graphics g=null;//定义图像类变量名,在窗体上获取
ImageEff imgeff=new ImageEff();//创建图像处理滤镜类对象
int[][] imgarr= {};
int[][] imgarr1= {};
int[][] imgarr2= {};//定义存储当前操作的图片的像素值数组
/*
* 构造方法 创建对象调用 适合在其中写初始化的代码
*/
public ImageListener() {
//定义给定图片的路径
String imgpath01="C:\\Users\\31491\\Pictures\\toux.jpg";
String imgpath02="C:\\Users\\31491\\Pictures\\ziji1.jpg";
String imgpath03="C:\\Users\\31491\\Pictures\\ziji2.jpg";
String imgpath04="C:\\Users\\31491\\Pictures\\bear.jpg";
//数组初始化
imgarr=imgeff.getimagepixelarry(imgpath01);
imgarr1 = imgeff.getimagepixelarry(imgpath01);
imgarr2=imgeff.getimagepixelarry(imgpath04);
}
/*
* 点击按钮时调用
*/
//"原图","反片","脸部提亮","马赛克","美白","轮廓提取","灰度","二值化","油画","图片融合","撤回"
public void actionPerformed(ActionEvent e) {
String btnstr=e.getActionCommand();//获取按钮上的字符串
System.out.println("点击了"+btnstr);
if(btnstr.equals("原图")) {
imgeff.drawimage01(imgarr,g);
}else if(btnstr.equals("反片")) {
imgeff.drawimage02(imgarr,g);
}else if(btnstr.equals("脸部提亮")) {
imgeff.drawimage03(imgarr,g);
}else if(btnstr.equals("马赛克")) {
imgeff.drawimage04(imgarr,g);
}else if(btnstr.equals("美白")) {
imgeff.drawimage05(imgarr,g);
}else if(btnstr.equals("轮廓提取")) {
imgeff.drawimage06(imgarr,g);
}else if(btnstr.equals("灰度")) {
imgeff.drawimage07(imgarr,g);
}else if(btnstr.equals("二值化")) {
imgeff.drawimage08(imgarr,g);
}else if(btnstr.equals("油画")) {
imgeff.drawimage09(imgarr,g);
}else if(btnstr.equals("图片融合")) {
imgeff.drawimage10(imgarr1,imgarr2,g);
}else if(btnstr.equals("撤回")) {
imgeff.drawimage11(imgarr,g);
}
}
}
图片处理效果类
- 将图片转为二维数组
public int[][] getimagepixelarry(String path) {
File file=new File(path);//将图片保存为文件
BufferedImage buffimg=null;//声明BufferedImage类型变量名
try {
buffimg=ImageIO.read(file);
} catch (IOException e) {
e.printStackTrace();
}
//获取图片的宽高
int w=buffimg.getWidth();
int h=buffimg.getHeight();
int[][] imgarr=new int[w][h];
//将图片的像素值保存到数组中
for(int i=0;i<w;i++) {
for(int j=0;j<h;j++) {
imgarr[i][j]=buffimg.getRGB(i, j);
}
}
return imgarr;
}
- 提供滤镜处理方法
1原图
public void drawimage01(int[][]imgarr,Graphics g) {
for(int i=0;i<imgarr.length;i++) {
for(int j=0;j<imgarr[i].length;j++) {
int rgb=imgarr[i][j];
Color color=new Color(rgb);
g.setColor(color);
g.fillRect(200+i,200+j,1,1);
}
}
}
2反片
r=255-color.getRed(); g=255-color.getGreen(); b=255-color.getBlue()
public void drawimage02(int[][] imgarr, Graphics g) {
for(int i=0;i<imgarr.length;i++) {
for(int j=0;j<imgarr[i].length;j++) {
int rgb=imgarr[i][j];
Color color=new Color(rgb);
int red=255-color.getRed();
int green=255-color.getGreen();
int blue=255-color.getBlue();
Color ncolor=new Color(red,green,blue);
g.setColor(ncolor);
g.fillRect(200+i, 200+j, 1, 1);
}
}
}
3脸部提亮
若图片颜色的r、g、b值大于220,则令新的画笔颜色r、g、b值为250,否则则令新的画笔颜色r、g、b在原有的基础上加30。若原有图片(r+b+g)/3小于等于100,则将画笔颜色设置为原有图片的颜色,否则则将画笔颜色设置为新的画笔颜色。
public void drawimage03(int[][] imgarr, Graphics g) {
for(int i=0;i<imgarr.length;i++) {
for(int j=0;j<imgarr[i].length;j++) {
int rgb=imgarr[i][j];
Color color=new Color(rgb);
int red=color.getRed();
int green=color.getGreen();
int blue=color.getBlue();
int gray=(red+green+blue)/3;
int nred=red>220? 250:red+30;
int ngreen=green>220? 250:green+30;
int nblue=blue>220? 250:blue+30;
Color ncolor=new Color(nred,ngreen,nblue);
if(gray<=100) {
g.setColor(color);
}else {
g.setColor(ncolor);
}
g.fillRect(200+i, 200+j, 1, 1);
}
}
}
4马赛克
将每个像素值放大一定数量
public void drawimage04(int[][] imgarr, Graphics g) {
for(int i=0;i<imgarr.length;i+=15) {
for(int j=0;j<imgarr[i].length;j+=15) {
int rgb=imgarr[i][j];
Color color=new Color(rgb);
g.setColor(color);
g.fillRect(200+i,200+j,15,15);
}
}
}
5美白
将原有图片颜色的r、g、b值在一定范围内放大,使放大的r、g、b值不超过255就可以
public void drawimage05(int[][] imgarr, Graphics g) {
for(int i=0;i<imgarr.length;i++) {
for(int j=0;j<imgarr[i].length;j++) {
int rgb=imgarr[i][j];
Color color=new Color(rgb);
int red=color.getRed();
int green=color.getGreen();
int blue=color.getBlue();
int nred=red+30>255? 255:red+30;
int ngreen=green+30>255? 255:green+30;
int nblue=blue+30>255? 255:blue+30;
Color ncolor=new Color(nred,ngreen,nblue);
g.setColor(ncolor);
g.fillRect(200+i,200+j,1,1);
}
}
}
6轮廓提取
图像轮廓处颜色值会发生较大的变化,要提取图像轮廓,则需比较轮廓处某点的颜色灰度值和其周围某点颜色灰度值。若两点之差的绝对值大于一定值时将画笔颜色设置为黑色,否则则将画笔颜色设置为白色。
public void drawimage06(int[][] imgarr, Graphics g) {
for(int i=0;i<imgarr.length-2;i++) {
for(int j=0;j<imgarr[i].length-2;j++) {
int rgb=imgarr[i][j];
Color color=new Color(rgb);
int red=color.getRed();
int green=color.getGreen();
int blue=color.getBlue();
int gray=(red+green+blue)/3;
int nrgb=imgarr[i+2][j+2];
Color ncolor=new Color(nrgb);
int nred=ncolor.getRed();
int ngreen=ncolor.getGreen();
int nblue=ncolor.getBlue();
int ngray=(nred+ngreen+nblue)/3;
if(Math.abs(gray-ngray)>15) {
g.setColor(Color.black);
}else {
g.setColor(Color.white);
}
g.fillRect(200+i, 200+j, 1, 1);
}
}
}
7灰度
-平均值法
nr=ng=nb=gray=(r+g+b)/3
-按一定比例(红色占比稍多些)
nr=ng=nb=gray=(r*0.41+g*0.36+b*0.23)
public void drawimage07(int[][] imgarr, Graphics g) {
for(int i=0;i<imgarr.length;i++) {
for(int j=0;j<imgarr[i].length;j++) {
int rgb=imgarr[i][j];
Color color=new Color(rgb);
int red=color.getRed();
int green=color.getGreen();
int blue=color.getBlue();
int gray=(red+green+blue)/3;
Color ncolor=new Color(gray,gray,gray);
g.setColor(ncolor);
g.fillRect(200+i, 200+j, 1, 1);
}
}
}
8二值化
新得到的图片只有两种颜色,即黑色与白色。若图片颜色的灰度值小于一定值,则将画笔颜色设置为黑、白的其中一种颜色,否则则将画笔颜色设置为剩下的一种颜色。
public void drawimage08(int[][] imgarr, Graphics g) {
for(int i=0;i<imgarr.length;i++) {
for(int j=0;j<imgarr[i].length;j++) {
int rgb=imgarr[i][j];
Color color=new Color(rgb);
int red=color.getRed();
int green=color.getGreen();
int blue=color.getBlue();
int gray=(red+green+blue)/3;
if(gray<=100) {
Color ncolor=new Color(0,0,0);
g.setColor(ncolor);
g.fillRect(200+i,200+j,1,1);
}else {
Color ncolor=new Color(255,255,255);
g.setColor(ncolor);
g.fillRect(200+i,200+j,1,1);
}
}
}
}
9油画
将原有图片的像素值扩大一定数量,且每个像素点不再是一个个小矩形,而是不等大小的圆,圆的外切矩形的长宽是随机值。
public void drawimage09(int[][] imgarr, Graphics g) {
for(int i=0;i<imgarr.length;i+=5) {
for(int j=0;j<imgarr[i].length;j+=5) {
int rgb=imgarr[i][j];
Color color=new Color(rgb);
Random random=new Random();
int r=random.nextInt(15)+5;
g.setColor(color);
g.fillOval(200+i, 200+j, r, r);
}
}
}
10图片融合
将多张图片按一定方式组合,则先需调整图片大小和比例,然后将多张图片转为二维数组,接着设置画笔颜色值,将多张图片的画笔起点设置在不同地方。
public void drawimage10(int[][] imgarr1,int[][] imgarr2, Graphics g) {
for(int i=0;i<imgarr1.length;i++) {
for(int j=0;j<imgarr1[i].length;j++) {
int rgb=imgarr1[i][j];
Color color=new Color(rgb);
g.setColor(color);
g.fillRect(200+i, 200+j, 1, 1);
}
}
for(int i=0;i<imgarr2.length;i++) {
for(int j=0;j<imgarr2[i].length;j++) {
int rgb=imgarr2[i][j];
Color color=new Color(rgb);
g.setColor(color);
g.fillRect(208+i, 270+j, 1, 1);
}
}
}