在上一篇博客的基础上,我们将实现更多的图像处理技术。
原图片
1. 灰度滤镜
效果:
原理:
灰度滤镜:
将颜色的RGB设置为相同的值即可使得图片为灰色,一般处理方法有:
1、取三种颜色的平均值
2、取三种颜色的最大值(最小值)
3、加权平均值:0.3R + 0.59G + 0.11*B
代码:(此处我们采取第一种处理方法)
private void drawHD(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int grayValue = (redValue + greenValue + blueValue) / 3;
color = new Color(grayValue, grayValue,grayValue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
2. 黑白滤镜
效果:
原理:
黑白滤镜:
顾名思义,就是图片的颜色只有黑色和白色,可以计算rgb的平均值arg,arg>=100,r=g=b=255,否则均为0
代码:
private void drawHB(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int avgValue = (redValue + greenValue + blueValue) / 3;
color = (avgValue >= 100)? new Color(255, 255, 255):new Color(0, 0, 0);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
3. 反向滤镜
效果:
原理:
反向滤镜:
就是RGB三种颜色分别取255的差值。
代码:
private void drawFX(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int reverseRedValue = 255 - redValue;
int reverseGreenValue = 255 - greenValue;
int reverseBlueValue = 255 - blueValue;
color = new Color(reverseRedValue,reverseGreenValue, reverseBlueValue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
4. 去色滤镜
效果:
原理:
去色滤镜
rgb三种颜色取三种颜色的最值的平均值。
代码:
private void drawQS(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int avgValue = (int)Math.floor((Math.min(Math.min(redValue, greenValue),blueValue)+Math.max(Math.max(redValue, greenValue),blueValue))/2);
color = new Color(avgValue,avgValue, avgValue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
5. 单色滤镜
效果:
原理:
单色滤镜
就是只保留一种颜色,其他颜色设为0
代码:(此处我们只保留红色)
private void drawHD(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int grayValue = (redValue + greenValue + blueValue) / 3;
color = new Color(grayValue, grayValue,grayValue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
6. 高斯模糊滤镜
参考资料:http://www.ruanyifeng.com/blog/2012/11/gaussian_blur.html
效果:
原理:
高斯模糊滤镜:
高斯模糊的原理就是根据正态分布使得每个像素点周围的像素点的权重不一致,
将各个权重(各个权重值和为1)与对应的色值相乘,所得结果求和为中心像素点新的色值。
我们需要了解的高斯模糊的公式:
我们用的是二维相互独立的高斯分布。假设我们有张图,由1000*1000像素点组成,对于每个需要高斯模糊处理的点(0,0)的像素值来说,我们需要用到其周围的一些像素点,如下图:
以中心点(0,0)为高斯分布的密度函数f(0,0)的值生成周围一群数的值,如下图:
然后,我们有这9个点的权重总和等于0.4787147,如果只计算这9个点的加权平均,还必须让它们的权重之和等于1,因此上面9个值还要分别除以0.4787147,得到最终的权重矩阵。如下图:
有了权重矩阵,就可以计算高斯模糊的值了。
假设现有9个像素点,灰度值(0-255)如下:
每个点乘以自己的权重值:
得到
将这9个值加起来,就是中心点的高斯模糊的值。
在代码中:我们分别对RGB用以上方法处理,图中用的是33的矩阵,我们也可以扩大到nn矩阵,代码中用5*5矩阵。
代码:
private void drawGS(){
//构造一个二维的高斯分布,由两个独立的高斯N(0,1.5)组成。我们要取(-1,-1),...,(1,1)九个点构成矩阵
double mean = 0; //高斯的参数期望,不需要改
double sigma = 6.0; // 高斯的参数平方差,可以改
int radius = 5; // 二维高斯矩阵的半径,可以改
double[][] norMaxtrix = new double[2*radius-1][2*radius-1]; // 正态密度的矩阵
double sumOfNormaxtrix = 0.0; //正态密度的矩阵的各个值的和
/*
以矩阵中心为f(0,0),生成高斯密度矩阵,i矩阵的行数,j列数
*/
for(int i=0;i<norMaxtrix.length;i++) {
for(int j=0;j<norMaxtrix[i].length;j++) {
norMaxtrix[i][j] = 1/Math.sqrt(2*Math.PI)*Math.exp(-((i-radius+1)-mean)*((i-radius+1)-mean)/(2*sigma*sigma))*1/Math.sqrt(2*Math.PI)*Math.exp(-((j-radius+1)-mean)*((j-radius+1)-mean)/(2*sigma*sigma));
// System.out.println(norMaxtrix[i][j]);
sumOfNormaxtrix += norMaxtrix[i][j];
}
}
/*
权重矩阵:密度矩阵的各个值除以正态密度的矩阵的各个值的和
*/
double[][] weightedMatrix = new double[2*radius-1][2*radius-1];
for(int i=0;i<weightedMatrix.length;i++) {
for(int j=0;j<weightedMatrix[i].length;j++) {
weightedMatrix[i][j] = norMaxtrix[i][j]/sumOfNormaxtrix;
// System.out.println(sumOfNormaxtrix);
// System.out.println(weightedMatrix[i][j]);
}
}
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
//确定中心元素可以取到的范围,并对每个元素分别提取RGB的整数值,分别赋予权重矩阵对应的值,然后把所有权重后的值相加。分别对RGB相同操作。
if(i>radius-1 && i <data.length-radius && j>radius-1 && j <data[i].length-radius) {
double sumredMatrix = 0;
double sumgreenMatrix = 0;
double sumblueMatrix = 0;
for(int k =0; k<weightedMatrix.length;k++) {
for(int l=0;l<weightedMatrix[k].length;l++) {
// System.out.println(i+(k-radius+1));
// System.out.println(j+(l-radius+1));
int v = data[i+(k-radius+1)][j+(l-radius+1)];
Color color = new Color(v);
sumredMatrix += color.getRed()*weightedMatrix[k][l];
sumgreenMatrix += color.getGreen()*weightedMatrix[k][l];
sumblueMatrix += color.getBlue()*weightedMatrix[k][l];
}
}
// System.out.println(avgredMatrix);
Color color = new Color((int)Math.floor(sumredMatrix),(int)Math.floor(sumgreenMatrix),(int)Math.floor(sumblueMatrix));
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}else{//对边缘的无法操作的元素,直接输出
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen();
int blueValue = color.getBlue();
color = new Color(redValue,greenValue, blueValue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
}
7. 怀旧滤镜
效果:
原理:
怀旧滤镜
怀旧滤镜公式
r = 0.393 * r + 0.769 * g + 0.189 * b
g = 0.349 * r + 0.686 * g + 0.168 * b
b = 0.272 * r + 0.534 * g + 0.131 * b
若大于255取255,若小于0取0
代码:
private void drawHJ(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int hjRed = ((int)(0.393 * redValue + 0.769 * greenValue + 0.189 * blueValue)<0)? 0:((int)(0.393 * redValue + 0.769 * greenValue + 0.189 * blueValue)>255)? 255:(int)(0.393 * redValue + 0.769 * greenValue + 0.189 * blueValue);
int hjGreen = ((int)(0.349 * redValue + 0.686 * greenValue + 0.168 * blueValue)<0)? 0:((int)(0.349 * redValue + 0.686 * greenValue + 0.168 * blueValue)>255)? 255:(int)(0.349 * redValue + 0.686 * greenValue + 0.168 * blueValue);
int hjBlue = ((int)(0.272 * redValue + 0.534 * greenValue + 0.131 * blueValue)<0)? 0:((int)(0.272 * redValue + 0.534 * greenValue + 0.131 * blueValue)>255)? 255:(int)(0.272 * redValue + 0.534 * greenValue + 0.131 * blueValue);
color = new Color(hjRed,hjGreen, hjBlue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
8. 熔铸滤镜
效果:
原理:
熔铸滤镜
公式: r = r128/(g+b +1);
g = g128/(r+b +1);
b = b*128/(g+r +1);
若大于255取255,若小于0取0
代码:(此处我们采取第一种处理方法)
private void drawRZ(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int RZRed = ((int)(128 * redValue/ (greenValue + blueValue+1))<0)?0: ((int)(128 * redValue/ (greenValue + blueValue+1))>255)?255:(int)(128 * redValue/ (greenValue + blueValue+1));
int RZGreen = ((int)(128 * greenValue /(redValue + blueValue+1))<0)?0:((int)(128 * greenValue /(redValue + blueValue+1))>255)?255:(int)(128 * greenValue /(redValue + blueValue+1));
int RZBlue = ((int)(128 * blueValue /(greenValue + redValue+1))<0)?0:((int)(128 * blueValue /(greenValue + redValue+1))>255)?255:(int)(128 * blueValue /(greenValue + redValue+1));
color = new Color(RZRed,RZGreen, RZBlue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
9. 冰冻滤镜
效果:
原理:
冰冻滤镜
公式: r = (r-g-b)*3/2;
g = (g-r-b)*3/2;
b = (b-g-r)*3/2;
代码:
private void drawBD(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int changedRed = (int)(redValue-greenValue-blueValue)*3/2;
int changedGreen = (int)(greenValue-redValue-blueValue)*3/2;
int changedBlue = (int)(blueValue-greenValue-redValue)*3/2;
int BDRed = (changedRed<0)?0: (changedRed>255)?255:changedRed;
int BDGreen = (changedGreen<0)?0: (changedGreen>255)?255:changedGreen;
int BDBlue = (changedBlue<0)?0: (changedBlue>255)?255:changedBlue;
color = new Color(BDRed,BDGreen, BDBlue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
10. 连环画滤镜
效果:
原理:
连环画滤镜
公式: R = |g – b + g + r| * r / 256
G = |b – g + b + r| * r / 256;
B = |b – g + b + r| * g / 256;
代码:
private void drawLLH(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int changedRed = (int)(Math.abs(greenValue-blueValue+greenValue+redValue)*redValue/256);
int changedGreen = (int)(Math.abs(-greenValue+blueValue+greenValue+redValue)*redValue/256);
int changedBlue = (int)(Math.abs(greenValue-blueValue+greenValue+redValue)*greenValue/256);
int LLHRed = (changedRed<0)?0: (changedRed>255)?255:changedRed;
int LLHGreen = (changedGreen<0)?0: (changedGreen>255)?255:changedGreen;
int LLHBlue = (changedBlue<0)?0: (changedBlue>255)?255:changedBlue;
color = new Color(LLHRed,LLHGreen, LLHBlue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
11. 褐色滤镜
效果:
原理:
褐色滤镜
公式: r = r * 0.393 + g * 0.769 + b * 0.189;
g = r * 0.349 + g * 0.686 + b * 0.168;
b = r * 0.272 + g * 0.534 + b * 0.131;
代码:
private void drawHS(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int changedRed = (int)(0.393*redValue+0.769*greenValue+0.189*blueValue);
int changedGreen = (int)(0.349*redValue+0.686*greenValue+0.168*blueValue);
int changedBlue = (int)(0.272*redValue+0.534*greenValue+0.131*blueValue);
int HSRed = (changedRed<0)?0: (changedRed>255)?255:changedRed;
int HSGreen = (changedGreen<0)?0: (changedGreen>255)?255:changedGreen;
int HSBlue = (changedBlue<0)?0: (changedBlue>255)?255:changedBlue;
color = new Color(HSRed,HSGreen, HSBlue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
所有用到代码
BuAction.java
import java.awt.Color;
import java.awt.Graphics;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Arrays;
import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileNameExtensionFilter;
//实现按钮监听器
//再加现拉杆改变的监听器
//一个类,可以实现多个接口
public class BuAction implements ActionListener, ChangeListener {
private Graphics g;
private int dValue = 1;
private String fName = "6.jpg";
// 用方法传参
public void setG(Graphics g) {
this.g = g;
}
// 拉杆拉动时发生
public void stateChanged(ChangeEvent e) {
// 获取事件源:
// 知道这个事件源,是一个JSlider对象
Object object = e.getSource();
// 强制转型成为JSlider
JSlider js = (JSlider) object;
// 获取当前的值
int v = js.getValue();
System.out.println("jslider当前的值是" + v);
this.dValue = v;
// 也画 一次
drawQBJImg();
}
// 按钮点击时发生
public void actionPerformed(ActionEvent e) {
// 通过事件对象 e,获取组件上的标签
String cmd = e.getActionCommand();
System.out.println("现在点击的是:" + cmd);
switch (cmd) {
case "去背景":
drawQBJImg();
break;
case "拉普拉斯":
break;
case "打开图片":
String fName = selectImg();
if (fName != null) {
this.fName = fName;
}
break;
case "灰度滤镜":
drawHD();
break;
case "黑白滤镜":
drawHB();
break;
case "反向滤镜":
drawFX();
break;
case "去色滤镜":
drawQS();
break;
case "单色滤镜":
drawDS();
break;
case "高斯模糊滤镜":
drawGS();
break;
case "怀旧滤镜":
drawHJ();
break;
case "熔铸滤镜":
drawRZ();
break;
case "冰冻滤镜":
drawBD();
break;
case "连环画滤镜":
drawLLH();
break;
case "褐色滤镜":
drawHS();
break;
}
}
// 打开文件选择框,得到返回选中文件绝对路径名
private String selectImg() {
JFileChooser chooser = new JFileChooser(); // 创建一个文件选择器
FileNameExtensionFilter filter = new FileNameExtensionFilter("JPG & PNG Images", "jpg", "png"); // 创建这个文件的规范
chooser.setFileFilter(filter); // 加上这个文件规范
int returnVal = chooser.showOpenDialog(new TextField()); // 返回值 点确定
if (returnVal == JFileChooser.APPROVE_OPTION) { // 判断是否选择为确定
// 得到选中文件的绝对路径名
String fName = chooser.getSelectedFile().getAbsolutePath();
System.out.println("选中的文件是: " + fName);
return fName;
}
return null;
}
// 只需要从源图片文件,读取一次数据,即可
// 将一张图片转化成一个int型癿二维数组
public int[][] getImagePixel(String image) {
File file = new File(image);
BufferedImage bi = null;
try {
bi = ImageIO.read(file);
} catch (Exception e) {
e.printStackTrace();
}
// 得到图片像素的宽和高
int w = bi.getWidth();
int h = bi.getHeight();
int[][] imIndex = new int[h][w];
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
int pixel = bi.getRGB(j, i); // i,j位置的Color值
imIndex[i][j] = pixel;// 每个像素点的color存入数组
}
}
return imIndex;
}
// 功能按钮方法:去背景图片
private void drawQBJImg() {
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
color = new Color(color.getRed(), color.getGreen(), color.getBlue());
g.setColor(color);
g.fillOval(j + 100, i + 100, dValue, dValue);
}
}
}
/*
灰度滤镜
将颜色的RGB设置为相同的值即可使得图片为灰色,一般处理方法有:
1、取三种颜色的平均值
2、取三种颜色的最大值(最小值)
3、加权平均值:0.3R + 0.59G + 0.11*B
*/
private void drawHD(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int grayValue = (redValue + greenValue + blueValue) / 3;
color = new Color(grayValue, grayValue,grayValue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
/*
黑白滤镜
顾名思义,就是图片的颜色只有黑色和白色,可以计算rgb的平均值arg,arg>=100,r=g=b=255,否则均为0
*/
private void drawHB(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int avgValue = (redValue + greenValue + blueValue) / 3;
color = (avgValue >= 100)? new Color(255, 255, 255):new Color(0, 0, 0);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
/*
反向滤镜
就是RGB三种颜色分别取255的差值。
*/
private void drawFX(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int reverseRedValue = 255 - redValue;
int reverseGreenValue = 255 - greenValue;
int reverseBlueValue = 255 - blueValue;
color = new Color(reverseRedValue,reverseGreenValue, reverseBlueValue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
/*
去色滤镜
rgb三种颜色取三种颜色的最值的平均值。
*/
private void drawQS(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int avgValue = (int)Math.floor((Math.min(Math.min(redValue, greenValue),blueValue)+Math.max(Math.max(redValue, greenValue),blueValue))/2);
color = new Color(avgValue,avgValue, avgValue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
/*
单色滤镜
就是只保留一种颜色,其他颜色设为0
*/
private void drawDS(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = 0;
int blueValue = 0;
color = new Color(redValue,greenValue, blueValue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
/*
高斯模糊滤镜
高斯模糊的原理就是根据正态分布使得每个像素点周围的像素点的权重不一致,
将各个权重(各个权重值和为1)与对应的色值相乘,所得结果求和为中心像素点新的色值。
我们需要了解的高斯模糊的公式:
*/
private void drawGS(){
//构造一个二维的高斯分布,由两个独立的高斯N(0,1.5)组成。我们要取(-1,-1),...,(1,1)九个点构成矩阵
double mean = 0; //高斯的参数期望,不需要改
double sigma = 6.0; // 高斯的参数平方差,可以改
int radius = 5; // 二维高斯矩阵的半径,可以改
double[][] norMaxtrix = new double[2*radius-1][2*radius-1]; // 正态密度的矩阵
double sumOfNormaxtrix = 0.0; //正态密度的矩阵的各个值的和
/*
以矩阵中心为f(0,0),生成高斯密度矩阵,i矩阵的行数,j列数
*/
for(int i=0;i<norMaxtrix.length;i++) {
for(int j=0;j<norMaxtrix[i].length;j++) {
norMaxtrix[i][j] = 1/Math.sqrt(2*Math.PI)*Math.exp(-((i-radius+1)-mean)*((i-radius+1)-mean)/(2*sigma*sigma))*1/Math.sqrt(2*Math.PI)*Math.exp(-((j-radius+1)-mean)*((j-radius+1)-mean)/(2*sigma*sigma));
// System.out.println(norMaxtrix[i][j]);
sumOfNormaxtrix += norMaxtrix[i][j];
}
}
/*
权重矩阵:密度矩阵的各个值除以正态密度的矩阵的各个值的和
*/
double[][] weightedMatrix = new double[2*radius-1][2*radius-1];
for(int i=0;i<weightedMatrix.length;i++) {
for(int j=0;j<weightedMatrix[i].length;j++) {
weightedMatrix[i][j] = norMaxtrix[i][j]/sumOfNormaxtrix;
// System.out.println(sumOfNormaxtrix);
// System.out.println(weightedMatrix[i][j]);
}
}
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
//确定中心元素可以取到的范围,并对每个元素分别提取RGB的整数值,分别赋予权重矩阵对应的值,然后把所有权重后的值相加。分别对RGB相同操作。
if(i>radius-1 && i <data.length-radius && j>radius-1 && j <data[i].length-radius) {
double sumredMatrix = 0;
double sumgreenMatrix = 0;
double sumblueMatrix = 0;
for(int k =0; k<weightedMatrix.length;k++) {
for(int l=0;l<weightedMatrix[k].length;l++) {
// System.out.println(i+(k-radius+1));
// System.out.println(j+(l-radius+1));
int v = data[i+(k-radius+1)][j+(l-radius+1)];
Color color = new Color(v);
sumredMatrix += color.getRed()*weightedMatrix[k][l];
sumgreenMatrix += color.getGreen()*weightedMatrix[k][l];
sumblueMatrix += color.getBlue()*weightedMatrix[k][l];
}
}
// System.out.println(avgredMatrix);
Color color = new Color((int)Math.floor(sumredMatrix),(int)Math.floor(sumgreenMatrix),(int)Math.floor(sumblueMatrix));
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}else{//对边缘的无法操作的元素,直接输出
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen();
int blueValue = color.getBlue();
color = new Color(redValue,greenValue, blueValue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
}
/*
怀旧滤镜
怀旧滤镜公式
r = 0.393 * r + 0.769 * g + 0.189 * b
g = 0.349 * r + 0.686 * g + 0.168 * b
b = 0.272 * r + 0.534 * g + 0.131 * b
若大于255取255,若小于0取0
*/
private void drawHJ(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int hjRed = ((int)(0.393 * redValue + 0.769 * greenValue + 0.189 * blueValue)<0)? 0:((int)(0.393 * redValue + 0.769 * greenValue + 0.189 * blueValue)>255)? 255:(int)(0.393 * redValue + 0.769 * greenValue + 0.189 * blueValue);
int hjGreen = ((int)(0.349 * redValue + 0.686 * greenValue + 0.168 * blueValue)<0)? 0:((int)(0.349 * redValue + 0.686 * greenValue + 0.168 * blueValue)>255)? 255:(int)(0.349 * redValue + 0.686 * greenValue + 0.168 * blueValue);
int hjBlue = ((int)(0.272 * redValue + 0.534 * greenValue + 0.131 * blueValue)<0)? 0:((int)(0.272 * redValue + 0.534 * greenValue + 0.131 * blueValue)>255)? 255:(int)(0.272 * redValue + 0.534 * greenValue + 0.131 * blueValue);
color = new Color(hjRed,hjGreen, hjBlue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
/*
熔铸滤镜
公式: r = r128/(g+b +1);
g = g128/(r+b +1);
b = b*128/(g+r +1);
若大于255取255,若小于0取0
*/
private void drawRZ(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int RZRed = ((int)(128 * redValue/ (greenValue + blueValue+1))<0)?0: ((int)(128 * redValue/ (greenValue + blueValue+1))>255)?255:(int)(128 * redValue/ (greenValue + blueValue+1));
int RZGreen = ((int)(128 * greenValue /(redValue + blueValue+1))<0)?0:((int)(128 * greenValue /(redValue + blueValue+1))>255)?255:(int)(128 * greenValue /(redValue + blueValue+1));
int RZBlue = ((int)(128 * blueValue /(greenValue + redValue+1))<0)?0:((int)(128 * blueValue /(greenValue + redValue+1))>255)?255:(int)(128 * blueValue /(greenValue + redValue+1));
color = new Color(RZRed,RZGreen, RZBlue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
/*
冰冻滤镜
公式: r = (r-g-b)*3/2;
g = (g-r-b)*3/2;
b = (b-g-r)*3/2;
*/
private void drawBD(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int changedRed = (int)(redValue-greenValue-blueValue)*3/2;
int changedGreen = (int)(greenValue-redValue-blueValue)*3/2;
int changedBlue = (int)(blueValue-greenValue-redValue)*3/2;
int BDRed = (changedRed<0)?0: (changedRed>255)?255:changedRed;
int BDGreen = (changedGreen<0)?0: (changedGreen>255)?255:changedGreen;
int BDBlue = (changedBlue<0)?0: (changedBlue>255)?255:changedBlue;
color = new Color(BDRed,BDGreen, BDBlue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
/*
连环画滤镜
公式: R = |g – b + g + r| * r / 256
G = |b – g + b + r| * r / 256;
B = |b – g + b + r| * g / 256;
*/
private void drawLLH(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int changedRed = (int)(Math.abs(greenValue-blueValue+greenValue+redValue)*redValue/256);
int changedGreen = (int)(Math.abs(-greenValue+blueValue+greenValue+redValue)*redValue/256);
int changedBlue = (int)(Math.abs(greenValue-blueValue+greenValue+redValue)*greenValue/256);
int LLHRed = (changedRed<0)?0: (changedRed>255)?255:changedRed;
int LLHGreen = (changedGreen<0)?0: (changedGreen>255)?255:changedGreen;
int LLHBlue = (changedBlue<0)?0: (changedBlue>255)?255:changedBlue;
color = new Color(LLHRed,LLHGreen, LLHBlue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
/*
褐色滤镜
公式: r = r * 0.393 + g * 0.769 + b * 0.189;
g = r * 0.349 + g * 0.686 + b * 0.168;
b = r * 0.272 + g * 0.534 + b * 0.131;
*/
private void drawHS(){
// 图像的二维数组
// 去从文件读取源图片:要考虑到一个性能问题
this.dValue = 1;
int[][] data = this.getImagePixel(fName);
for (int i = 0; i < data.length; i += this.dValue) {
for (int j = 0; j < data[i].length; j += dValue) {
int v = data[i][j]; // i,j这个位置的像素color
Color color = new Color(v);
int redValue = color.getRed(); // 解析color对象的红色的值
int greenValue = color.getGreen(); // 解析color对象的绿色
int blueValue = color.getBlue(); // 解析color对象的蓝色值
int changedRed = (int)(0.393*redValue+0.769*greenValue+0.189*blueValue);
int changedGreen = (int)(0.349*redValue+0.686*greenValue+0.168*blueValue);
int changedBlue = (int)(0.272*redValue+0.534*greenValue+0.131*blueValue);
int HSRed = (changedRed<0)?0: (changedRed>255)?255:changedRed;
int HSGreen = (changedGreen<0)?0: (changedGreen>255)?255:changedGreen;
int HSBlue = (changedBlue<0)?0: (changedBlue>255)?255:changedBlue;
color = new Color(HSRed,HSGreen, HSBlue);
g.setColor(color);
g.fillRect(j+100, i+100, dValue, dValue);
}
}
}
}
DrawPantiner.java
import java.awt.FlowLayout;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JSlider;
//选择图片文件;使用菜单
public class DrawPantiner extends JFrame{
创建监听器:原来方法内的局部变量,变为属性,其他方法可访问
//一个实现ActionListener接口的监听器,可以加给多个按钮和菜单
private BuAction baAction = new BuAction();
public void showUI() {
this.setTitle("美颜色相机 v0.1");
this.setSize(1200,1200);
FlowLayout flowLayout = new FlowLayout();
this.setLayout(flowLayout);
JButton button = new JButton("去背景");
this.add(button);
JButton buttonMP = new JButton("拉普拉斯");
this.add(buttonMP);
JButton buttonYH = new JButton("油画");
this.add(buttonYH);
JButton buttonHD = new JButton("灰度滤镜");
this.add(buttonHD);
JButton buttonHB = new JButton("黑白滤镜");
this.add(buttonHB);
JButton buttonFX = new JButton("反向滤镜");
this.add(buttonFX);
JButton buttonQS = new JButton("去色滤镜");
this.add(buttonQS);
JButton buttonDS = new JButton("单色滤镜");
this.add(buttonDS);
JButton buttonGS = new JButton("高斯模糊滤镜");
this.add(buttonGS);
JButton buttonHJ = new JButton("怀旧滤镜");
this.add(buttonHJ);
JButton buttonRZ = new JButton("熔铸滤镜");
this.add(buttonRZ);
JButton buttonBD = new JButton("冰冻滤镜");
this.add(buttonBD);
JButton buttonLHH = new JButton("连环画滤镜");
this.add(buttonLHH);
JButton buttonHS = new JButton("褐色滤镜");
this.add(buttonHS);
//拉杆控制
JSlider js = new JSlider();
js.setMaximum(50);
js.setValue(10);
this.add(js);
//把菜单条加到界面上
JMenuBar mbBar = getMB();
this.setJMenuBar(mbBar);
this.setVisible(true);
this.setDefaultCloseOperation(3);
Graphics graphics = this.getGraphics();
//调用方法,把画布给传进去
baAction.setG(graphics);
//把监听器加给拉杆和按钮:
button.addActionListener(baAction);
buttonMP.addActionListener(baAction);
buttonYH.addActionListener(baAction);
buttonHD.addActionListener(baAction);
buttonHB.addActionListener(baAction);
buttonFX.addActionListener(baAction);
buttonQS.addActionListener(baAction);
buttonDS.addActionListener(baAction);
buttonGS.addActionListener(baAction);
buttonHJ.addActionListener(baAction);
buttonRZ.addActionListener(baAction);
buttonBD.addActionListener(baAction);
buttonLHH.addActionListener(baAction);
buttonHS.addActionListener(baAction);
js.addChangeListener(baAction);
}
public JMenuBar getMB() {
JMenuBar mb = new JMenuBar();
JMenu miFile = new JMenu("文件");
//再创建菜单下面的菜单项:
JMenuItem miOpen = new JMenuItem("打开图片");
miOpen.addActionListener(baAction);
JMenuItem miSave = new JMenuItem("保存图片");
miSave.addActionListener(baAction);
miFile.add(miOpen);
miFile.add(miSave);
mb.add(miFile);
return mb;
}
public static void main(String[] args) {
DrawPantiner lo = new DrawPantiner();
lo.showUI();
}
}