一、思路分析

一款简易美颜相机的功能我们可以简单分为两大块:1.图像处理    2.功能区

最终的效果图如下:

二、代码分析

图像处理工具的本质是处理像素点,而像素点的本质就是一种颜色,每一个像素点都有RGB三原色(0-255),0-255为一个字节。

图像处理知识:

  1. 图像处理的本质是在修改图片的像素值,而每一个像素点的本质是RGB三原色组成,其值范围0-255
  2. 图片的本质是一个int型的二维数组,所以图像 = int[ ] [ ];
  3. Color类可以实现数字颜色的转化。色即是数,数即是色。
  4. (1)RGB数字构成颜色:Color color = new Color(200,100,150); 其值在0-255之间

(2)int数字构成颜色:Color color = new Color(842179),其值在int范围内即可。Int最大到21亿

因为高位补1会超过255.

获取RGB三原色的分量值:

1.取出所有的像素值,把像素值转为Color对象,通过调用Color对象的getRed,getGreen,getBlue方法获取

2.通过将像素值右移相应的位数,再进行与操作

  1. 左移运算: int pixel = buffimage.getRGB(j, i);

1Byte(字节) = 8bit(位)

位运算:

在Java中int是有4个字节,RGB是三个字节的长度(0-255是一个字节),通过左移运算      把三个Byte合成了一个int,1Byte(字节) = 8bit(位)。R红色<<移动了16位,G绿色<<移动了8位,B蓝色不移动,通过位移操作总共移动了24位。

源代码:

这些滤镜就是一些算法,对图片的像素点RGB三原色进行修改,下面我讲一下这些滤镜效果的实现思路:

  • 这些滤镜就是一些算法,对图片的像素点RGB三原色进行修改。
  • 下面我讲一下这些滤镜效果的实现思路
  • 马赛克效果:在固定范围内放大像素点。
  • 灰度效果:1.取RGB三种颜色的平均值,则画出灰度图
  • 2.取三种颜色的最大值/最小值
  • 黑白滤镜:计算RGB三原色平均值,如果平均值>=100,则平均值为255,不是,平均值为0
  • 去色滤镜:RGB取三种颜色的最大值和最小值的平均值
  • 单色滤镜:就是只保留一种颜色,其他颜色设为0
  • 底片/反向滤镜:就是RGB三种颜色分别取255的差值
  • 怀旧滤镜:R = 0.393r + 0.769g + 0.189b
  • G = 0.349r + 0.686g + 0.168b
  • B = 0.272r + 0.534g + 0.131b
  • 褐色滤镜: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;
  • 连环画滤镜:公式: R = |g – b + g + r| * r / 256

    G = |b – g + b + r| * r / 256;

    B = |b – g + b + r| * g / 256;

  • 冰冻滤镜:公式: r = (r-g-b)*3/2; 
                                  g = (g-r-b)*3/2; 
                                  b = (b-g-r)*3/2;

  • 熔铸滤镜:公式: r = r*128/(g+b +1); 
                                 g = g*128/(r+b +1); 
                                 b = b*128/(g+r +1);

  • 浮雕效果:用当前点的RGB值减去相邻点的RGB值并加上128作为新的RGB值

  • 放大镜:不要跳过像素点来放大

  • Java程序真正是运行在我们的虚拟机上面的,程序>jvm(虚拟机)>os>总线>屏幕。
  • 利用缓冲区可以加快像素点的绘制速度,思路:把所有处理好的像素点先存入缓冲区,然后在屏幕上一次性显示出来。缓冲区它也是个容器。
  • 图像消失问题是因为组件重绘问题。
  • 除了接口,类里面也可以定义常量,常量可以直接通过类名来调用。

图像重绘问题:

  • 所有的swing包下的每一个组件都有一个paint方法,paint方法的作用:绘制组件本身。
  • swing包下的每一个组件都要通过调用paint函数把组件的效果显示在我们的屏幕上。
  • 当改变窗体的状态(隐藏,改变大小)都会导致窗体上所有的swing组件重新/自动调用paint方法。
  • 解决办法:让组件在重绘的过程中,把我们的图像显示效果也一起画一遍。
  • 解决图像重绘问题:1.重写组件的paint方法,添加paint方法绘制组件的功能
  • 2.保存图像数据
  • g.drawImage(img, x, x, width, height, observer)
  • img:画哪张图片  x,y画在哪个位置,图片的左上角    最后一个暂时用不到,给null

三、代码实现

package com.gch.filterarithmetic;import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;/**滤镜算法*/
public class PixelUI {/**图像处理界面*/public void showUI(){JFrame win = new JFrame("PC版美颜相机");win.setSize(1000,650);win.setLocationRelativeTo(null);win.setDefaultCloseOperation(3);// 设置边框/边界布局:BorderLayout 用这种边框布局,一个方向只能加一个组件win.setLayout(new BorderLayout());// 面板对象/桌布:JPanel 面板对象的默认颜色和窗体同色// 功能区:eastPanelJPanel eastPanel = new JPanel();// 设置功能区面板对象的背景色eastPanel.setBackground(Color.yellow);// 设置功能区面板对象的大小eastPanel.setPreferredSize(new Dimension(120,0));// 把功能区面板对象添加到窗体上 并且设置功能区的位置win.add(eastPanel,BorderLayout.EAST);// 创建事件处理类对象ButtonMouse mouse = new ButtonMouse();// 功能区按钮的添加// 定义字符串数组保存功能区按钮的名称String[] functionButton = {"原图","马赛克","灰度","黑白","去色","单色","底片/反向","怀旧","褐色","连环画","冰冻","熔铸","浮雕","放大镜","左转","右转","撤回"};for(int i = 0;i < functionButton.length;i++){// 定义按钮添加JButton btn = new JButton(functionButton[i]);// 把按钮添加到功能区面板eastPanel.add(btn);// 给按钮添加动作监听器:绑定事件处理类btn.addActionListener(mouse);}// 自定义面板类:MyPanel// 图像显示区/内容显示区:drawPanelMyPanel drawPanel = new MyPanel();// 设置图像显示区的背景色drawPanel.setBackground(Color.LIGHT_GRAY);// 把图像显示区添加到窗体上并设置图像显示区的位置win.add(drawPanel, BorderLayout.CENTER);// 设置窗体显示可见win.setVisible(true);// 画笔更新,画笔的获取要在内容显示区,直接传内容显示区对象/面板对象mouse.setG(drawPanel);}
}
package com.gch.filterarithmetic;import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;/**自定义面板类:图像显示区/内容显示区*/
public class MyPanel extends JPanel {// 定义缓冲区,保存传递过来的当前图像的缓冲对象private BufferedImage buff;/**定义set方法,初始化属性*/public void setBuff(BufferedImage buff) {this.buff = buff;}/**重写绘制组件的paint方法*/@Overridepublic void paint(Graphics g){// 1.保留绘制组件本身的功能:调用父类的方法super.paint(g); // super:表示当前类的父类对象// 2.绘制当前的图像功能,把画好的缓冲区buff传递过来g.drawImage(buff, 0 , 0 , null);}
}
package com.gch.filterarithmetic;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;/**事件处理类:给按钮添加动作监听器*/
public class ButtonMouse implements ActionListener {// 定义保存当前图像的缓冲区private BufferedImage buff;/**定义get方法,获取属性*/public BufferedImage getBuff() {return buff;}// 定义缓冲区数组,保存图层的数组private BufferedImage[] buffArr = new   BufferedImage[100];// 定义操作数组的下标private int index = 0;// 保存当前的有效图层private int count = 0;// 标记位public int flag = 1;// 定义图像显示区/内容显示区对象private MyPanel drawPanel;// 定义画笔对象,保存传递过来的画笔对象private Graphics g;/**定义set方法,初始化属性*/public void setG(MyPanel drawPanel) {this.drawPanel = drawPanel;}/**事件处理方法:动作监听器方法*/@Overridepublic void actionPerformed(ActionEvent e) {//每次画之前重新获取画笔,可以让画笔的获取实时更新g = drawPanel.getGraphics();// 指定图片路径String path = "C:\\Users\\A.G.H\\Pictures\\Camera Roll\\t0118a001acf2c4dc77.jpg";// 把指定路径的图片转换为int型的二维数组,获取指定图片路径的像素点的像素值int[][] pixelArr = getImagePixel(path);// 获取按钮上的内容String buttonName = e.getActionCommand();// 根据不同的按钮选择来实现不同的滤镜算法switch (buttonName){case "原图":masterPixel(pixelArr);break;case "马赛克":mosaicPixel(pixelArr);break;case "灰度":grayPixel(pixelArr);break;case "黑白":blackWhitePixel(pixelArr);break;case "去色":desaturatePixel(pixelArr);break;case "单色":singleColorPixel(pixelArr);break;case "底片/反向":artworkPixel(pixelArr);break;case "怀旧":retroPixel(pixelArr);break;case "褐色":brownPixel(pixelArr);break;case "连环画":comicsPixel(pixelArr);break;case "冰冻":freezePixel(pixelArr);break;case "熔铸":castingPixel(pixelArr);break;case "浮雕":reliefPixel(pixelArr);break;case "放大镜":enlargePixel(pixelArr);break;case "左转":leftPixel(pixelArr);break;case "右转":rightPixel(pixelArr);break;}if("撤回".equals(buttonName)) {//取出最后一个图层//把当前图层更新为撤回的图层buff = buffArr[--count];index = count;System.out.println("buff=" +buff + "count="+count);}else {//保存当前图层buffArr[index] = buff; //每按一次按钮就保存一次count = index; //记录有效图层index++;System.out.println("index="+index);}//更新缓冲区对象后再把当前缓冲区传递给自定义类MyPaneldrawPanel.setBuff(buff); //每更新一次就传一次//刷新面板drawPanel.repaint();}/**将图片转换为int型的二维数组,获取图片像素的宽高,获取每个像素点的像素值* 获取指定路径图片的像素点的像素值* @param path:指定图片路径* @return:返回保存指定路径图片像素点的像素值的二维数组*/public int[][] getImagePixel(String path){// 创建文件对象File file = new File(path);// BufferedImage:图像缓冲区,图片数据的封装类BufferedImage bufferedImage = null;// 用输入流读取指定文件的数据try {bufferedImage = ImageIO.read(file);} catch (IOException e) {throw new RuntimeException(e);}// 获取图片像素的宽高int w = bufferedImage.getWidth(); // 宽:对应二维数组的列int h = bufferedImage.getHeight(); // 高:对应二维数组的行// 保存到二维数组int[][] pixelArr = new int[h][w];// 遍历二维数组的每一个元素,通过双层循环遍历整个图片的像素点for(int i = 0;i < h;i++){for(int j = 0;j < w;j++){// 通过图像缓冲区bufferedImage对象的getRGB()方法获取每个像素点的像素值int pixel = bufferedImage.getRGB(j, i);// 把每个像素点的像素值保存到二维数组中pixelArr[i][j] = pixel;}}// 返回保存指定图片像素点的像素值的二维数组return pixelArr;}/*** 原图效果* @param pixelArr:保存图片像素点的像素值的二维数组*/public void masterPixel(int[][]pixelArr) {buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);//把像素点存到缓冲区里      缓冲区它也是个容器//2.获取缓冲区的画笔对象   buffG缓冲画笔  把像素点画到缓冲区里面Graphics  buffG =  buff.getGraphics();for(int i=0;i<pixelArr.length;i++) {for(int j=0;j<pixelArr[i].length;j++) {//取出所有的像素值int pixel =pixelArr[i][j];//把像素值转为Color对象Color color  = new Color(pixel);//把所有的像素点画在缓冲区里面//把画笔设置成当前颜色buffG.setColor(color);//绘制出当前颜色的像素点buffG.fillRect(j, i, 1, 1);}}//把图片显示在窗体上  缓冲区是个组件,如果你不把它显示出来,根本就看不见,缓冲区它是个图片  缓冲区/缓存图片g.drawImage(buff, 0, 0,null);   //drawImage方法它重载了好多次}/**马赛克效果:在固定范围内放大像素点*/public void mosaicPixel(int[][]pixelArr) {//创建缓冲区的对象 BufferedImage buff = new  BufferedImage(width, height, imageType)   常量,可以直接通过类名来调用buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);//2.获取缓冲区的画笔对象   buffG缓冲画笔  把像素点画到缓冲区里面Graphics  buffG =  buff.getGraphics();for(int i=0;i<pixelArr.length;i+=10) {   //放大了几倍,就跳过几个像素for(int j=0;j<pixelArr[i].length;j+=10) {//取出图片的所有像素值int  pixel =  pixelArr[i][j];//把像素值转为Color对象Color color = new Color(pixel);//把画笔对象设置成当前颜色buffG.setColor(color);//绘制出当前颜色的像素点   因为每一个像素点的位置是不一样的buffG.fillRect(j, i, 10, 10);  //放大了10倍数}}g.drawImage(buff, 0, 0, null);}/**灰度效果*/public void grayPixel(int[][]pixelArr) {//创建缓冲区对象buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);//2.获取缓冲区的画笔对象   buffG缓冲画笔  把像素点画到缓冲区里面Graphics  buffG =  buff.getGraphics();for(int i=0;i<pixelArr.length;i++) {for(int j=0;j<pixelArr[i].length;j++) {//取出所有的像素值int pixel = pixelArr[i][j];//把像素值转为Color对象Color color = new Color(pixel);//取RGB平均值,则画成灰度图int red = color.getRed();int green = color.getGreen();int blue = color.getBlue();int ave = (red+green+blue)/3;//把平均值作为三原色的基础值Color nc = new Color(ave,ave,ave);buffG.setColor(nc);buffG.fillRect(j, i, 1, 1);}}g.drawImage(buff, 0, 0, null);}//2.通过将像素值右移得到RGB三原色的分量值public void drawPixel4(int[][]pixelArr) {//创建缓冲区对象buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);//2.获取缓冲区的画笔对象   buffG缓冲画笔  把像素点画到缓冲区里面Graphics  buffG =  buff.getGraphics();for(int i=0;i<pixelArr.length;i++) {for(int j=0;j<pixelArr[0].length;j++) {//取出所有的像素值int pixel = pixelArr[i][j];//通过右移取出pixel像素中的三原色int red = (pixel>>16)&0xFF;  //位运算:只有1&1=1int green = (pixel>>8)&0xFF;int blue = (pixel>>0)&0xFF;//取RGB平均值int ave = (red+green+blue)/3;//把平均值作为三原色的初始值Color nc = new Color(ave,ave,ave);buffG.setColor(nc);buffG.fillRect(j, i, 1, 1);}}g.drawImage(buff, 0, 0, null);}//3.取三种颜色的最大值来实现灰度滤镜public void drawPixel5(int[][]pixelArr) {//创建缓冲区对象buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);//2.获取缓冲区的画笔对象   buffG缓冲画笔  把像素点画到缓冲区里面Graphics  buffG =  buff.getGraphics();for(int i=0;i<pixelArr.length;i++) {for(int j=0;j<pixelArr[i].length;j++) {//取出所有的像素值int pixel = pixelArr[i][j];//通过将像素值右移得到RGB三原色分量值int red  = (pixel>>16)&0xFF;int green =(pixel>>8)&0xFF;int blue =(pixel>>0)&0xFF;int tempmax = Math.max(red, green);     //int tempmax = (red>green)?red:green;int max =Math.max(tempmax, blue);     //int max = (tempmax>blue)?tempmax:blue;//把三种颜色最大值作为三原色的初始值Color nc = new Color(max,max,max);//把画笔设置成当前颜色buffG.setColor(nc);buffG.fillRect(j, i, 1, 1);}}g.drawImage(buff, 0, 0, null);}//4.取三种颜色的最小值来实现灰度滤镜public void drawPixel6(int[][]pixelArr) {//创建缓冲区对象buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);//2.获取缓冲区的画笔对象   buffG缓冲画笔  把像素点画到缓冲区里面Graphics  buffG =  buff.getGraphics();for(int i=0;i<pixelArr.length;i++) {for(int j=0;j<pixelArr[0].length;j++) {//取出所有的像素值int pixel = pixelArr[i][j];//通过将像素值右移得到RGB三原色分量值int red = (pixel>>16)&0xFF;int green =(pixel>>8)&0xFF;int blue =(pixel>>0)&0xFF;int tempmin = Math.min(red, green);      //int tempmin = (red<green)?red:green;int min = Math.min(tempmin, blue);       //int min =(tempmin<blue)?tempmin:blue;//把三原色的最小值作为RGB三原色的初始值Color color = new Color(min,min,min);buffG.setColor(color);buffG.fillRect(j, i, 1, 1);}}g.drawImage(buff,0, 0, null);}/**黑白滤镜*/public void blackWhitePixel(int[][]pixelArr) {//创建缓冲区对象buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);//2.获取缓冲区的画笔对象   buffG缓冲画笔  把像素点画到缓冲区里面Graphics  buffG =  buff.getGraphics();for(int i=0;i<pixelArr.length;i++) {for(int j=0;j<pixelArr[i].length;j++) {int pixel = pixelArr[i][j];//通过将像素值右移得到RGB三原色的分量值int red = (pixel>>16)&0xFF;int green =(pixel>>8)&0xFF;int blue = (pixel>>0)&0xFF;//计算RGB三原色平均值int ave = (red+green+blue)/3;if(ave>=100) {ave = 255;}else {ave = 0;}//将ave设为RGB三原色初始值Color color = new Color(ave,ave,ave);buffG.setColor(color);buffG.fillRect(j, i, 1, 1);}}g.drawImage(buff, 0, 0, null);}/**去色滤镜*/public void desaturatePixel(int[][]pixelArr) {//创建缓冲区对象buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);//2.获取缓冲区的画笔对象   buffG缓冲画笔  把像素点画到缓冲区里面Graphics  buffG =  buff.getGraphics();for(int i=0;i<pixelArr.length;i++) {for(int j=0;j<pixelArr[i].length;j++) {//取出所有的像素值int pixel = pixelArr[i][j];//把像素值右移得到RGB三原色分量值int red = (pixel>>16)&0xFF;int green =(pixel>>8)&0xFF;int blue = (pixel>>0)&0xFF;//取RGB三原色的最大值int tempmax = Math.max(red, green);int max = Math.max(tempmax, blue);//取RGB三原色的最小值int tempmin =Math.min(red, green);int min =Math.min(tempmin, blue);//取RGB三原色最大值和最小值的平均值int ave = (max+min)/2;//把平均值设为RGB三原色的初始值Color color = new Color(ave,ave,ave);buffG.setColor(color);buffG.fillRect(j, i, 1, 1);}}g.drawImage(buff, 0, 0, null);}/**单色滤镜*/public void singleColorPixel(int[][]pixelArr) {//创建缓冲区对象buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);//2.获取缓冲区的画笔对象   buffG缓冲画笔  把像素点画到缓冲区里面Graphics  buffG =  buff.getGraphics();for(int i=0;i<pixelArr.length;i++) {for(int j=0;j<pixelArr[i].length;j++) {//取出所有的像素点int pixel = pixelArr[i][j];//把像素点转为Color对象Color color = new Color(pixel);//获取RGB三原色分量值int red = color.getRed();int green = color.getGreen();int blue = color.getBlue();//只保留一个颜色Color nc = new Color(red,0,0);buffG.setColor(nc);buffG.fillRect(j, i, 1, 1);}}g.drawImage(buff,0,0, null);}/**底片/反向滤镜*/public void artworkPixel(int [][]pixelArr) {//创建缓冲区对象buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);//2.获取缓冲区的画笔对象   buffG缓冲画笔  把像素点画到缓冲区里面Graphics  buffG =  buff.getGraphics();for(int i=0;i<pixelArr.length;i++) {for(int j=0;j<pixelArr[i].length;j++) {//取出所有的像素值int pixel = pixelArr[i][j];//把像素值右移得到RGB三原色的分量值int red = 255 -(pixel>>16)&0xFF;int green = 255-(pixel>>8)&0xFF;int blue = 255 -(pixel>>0)&0xFF;//把分量值设为RGB三原色初始值Color color = new Color(red,green,blue);buffG.setColor(color);buffG.fillRect(j, i, 1, 1);}}g.drawImage(buff, 0, 0, null);}/**怀旧滤镜*/public void retroPixel(int[][]pixelArr) {//创建缓冲区对象buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);//2.获取缓冲区的画笔对象   buffG缓冲画笔  把像素点画到缓冲区里面Graphics  buffG =  buff.getGraphics();for(int i=0;i<pixelArr.length;i++) {for(int j=0;j<pixelArr[i].length;j++) {//取出所有的像素值int pixel =pixelArr[i][j];//把像素值右移得到RGB三原色分量值int red = (pixel>>16)&0xFF;///  System.out.println("red="+red);int green = (pixel>>8)&0xFF;//  System.out.println("green="+green);int blue =(pixel>>0)&0xFF;// System.out.println("blue="+blue);int R = (int)(0.393*red+0.769*green+0.189*blue);if(R>255) {R=255;}// System.out.println("R="+R);int G = (int)(0.349*red+0.686*green+0.168*blue);if(G>255) {G=255;}//System.out.println("G="+G);int B = (int)(0.272*red+0.534*green+0.131*blue);if(B>255) {B=255;}//System.out.println("B="+B);//把新的RGB值设为RGB三原色Color color = new Color(R,G,B);buffG.setColor(color);buffG.fillRect(j, i, 1, 1);}}g.drawImage(buff, 0, 0, null);}/**褐色滤镜*/public void brownPixel(int pixelArr[][]) {//创建缓冲区对象buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);//2.获取缓冲区的画笔对象   buffG缓冲画笔  把像素点画到缓冲区里面Graphics  buffG =  buff.getGraphics();for(int i=0;i<pixelArr.length;i++) {for(int j=0;j<pixelArr[0].length;j++) {int pixel = pixelArr[i][j];int red = (pixel>>16)&0xFF;int green = (pixel>>8)&0xFF;int blue = (pixel>>0)&0xFF;//褐色滤镜算法red = (int)(red*0.393+green*0.769+blue*0.189);if(red>255) {red=255;}green = (int)(red*0.349+green*0.686+blue*0.168);if(green>255) {green=255;}blue = (int)(red*0.272+green*0.534+blue*0.131);if(blue>255) {blue = 255;}//把新的RGB值设为三原色初始值Color color = new Color(red,green,blue);buffG.setColor(color);buffG.fillRect(j, i, 1, 1);}}g.drawImage(buff, 0, 0, null);}/**连环画滤镜*/public void comicsPixel(int[][]pixelArr) {//创建缓冲区对象buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);//2.获取缓冲区的画笔对象   buffG缓冲画笔  把像素点画到缓冲区里面Graphics  buffG =  buff.getGraphics();for(int i=0;i<pixelArr.length;i++) {for(int j=0;j<pixelArr[i].length;j++) {//取出所有的像素点int pixel = pixelArr[i][j];int R = (pixel>>16)&0xFF;int G = (pixel>>8)&0xFF;int B = (pixel>>0)&0xFF;R = Math.abs(G-B+G+R)*R/256;if(R>255) {R=255;}G = Math.abs(B-G+B+R)*R/256;if(G>255) {G=255;}B = Math.abs(B-G+B+R)*G/256;if(B>255) {B=255;}Color color = new Color(R,G,B);buffG.setColor(color);buffG.fillRect(j, i, 1, 1);}}g.drawImage(buff, 0, 0, null);}/**冰冻滤镜*/public void freezePixel(int pixelArr[][]) {//创建缓冲区对象buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);//2.获取缓冲区的画笔对象   buffG缓冲画笔  把像素点画到缓冲区里面Graphics  buffG =  buff.getGraphics();for(int i=0;i<pixelArr.length;i++) {for(int j=0;j<pixelArr[i].length;j++) {int pixel = pixelArr[i][j];int R = (pixel>>16)&0xFF;int G = (pixel>>8)&0xFF;int B = (pixel>>0)&0xFF;R = (R-G-B)*3/2;if(R<0) {R=0;}else if(R>255) {R=255;}//System.out.println("R="+R);G = (G-R-B)*3/2;if(G<0) {G=0;}else if(G>255) {G=255;}// System.out.println("G="+G);B = (B-G-R)*3/2;if(B<0) {B=0;}else if(B>255) {B=255;}//   System.out.println("B="+B);Color color = new Color(R,G,B);buffG.setColor(color);buffG.fillRect(j, i, 1, 1);}}g.drawImage(buff, 0, 0, null);}/**熔铸滤镜*/public void castingPixel(int[][]pixelArr) {//创建缓冲区对象buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);//2.获取缓冲区的画笔对象   buffG缓冲画笔  把像素点画到缓冲区里面Graphics  buffG =  buff.getGraphics();for(int i=0;i<pixelArr.length;i++) {for(int j=0;j<pixelArr[0].length;j++) {int pixel = pixelArr[i][j];int R = (pixel>>16)&0xFF;int G = (pixel>>8)&0xFF;int B = (pixel>>0)&0xFF;R = R*128/(G+B+1);if(R<0) {R=0;}else if(R>255){R =255;}G = G*128/(R+B+1);if(G<0) {G=0;}else if(G>255) {G=255;}B = B*128/(G+R+1);if(B<0) {B=0;}else if(B>255) {B=255;}//Color color = new Color(R,G,B);buffG.setColor(color);buffG.fillRect(j, i,1,1);}}g.drawImage(buff, 0, 0, null);}/**浮雕效果*/public void reliefPixel(int[][]pixelArr) {//创建缓冲区对象buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);//2.获取缓冲区的画笔对象   buffG缓冲画笔  把像素点画到缓冲区里面Graphics  buffG =  buff.getGraphics();for(int i =0;i<pixelArr.length-1;i++) {for(int j=0;j<pixelArr[0].length-1;j++) {int pixel0 = pixelArr[i][j];Color color0 = new Color(pixel0);int R0 =  color0.getRed();int G0 = color0.getGreen();int B0 = color0.getBlue();int pixel1 = pixelArr[i+1][j+1];Color color1 = new Color(pixel1);int R1 = color1.getRed();int G1 = color1.getGreen();int B1 = color1.getBlue();int NR = R0-R1+128;if(NR<0) {NR = 0;}else if(NR>255){NR = 255;}int NG = G0-G1+128;if(NG<0) {NG = 0;}else if(NG>255) {NG = 255;}int NB = B0-B1+128;if(NB<0) {NB = 0;}else if(NB>255) {NB = 255;}Color nc = new Color(NR,NG,NB);buffG.setColor(nc);buffG.fillRect(j, i, 1, 1);}}g.drawImage(buff, 0, 0, null);}/**放大镜*/public void enlargePixel(int[][]pixelArr) {buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);Graphics  buffG =  buff.getGraphics();for(int i=0;i<pixelArr.length;i++) {   //放大了几倍,就跳过几个像素for(int j=0;j<pixelArr[i].length;j++) {//取出图片的所有像素值int  pixel =  pixelArr[i][j];//把像素值转为Color对象Color color = new Color(pixel);//把画笔对象设置成当前颜色buffG.setColor(color);//绘制出当前颜色的像素点   因为每一个像素点的位置是不一样的buffG.fillRect(j, i, 1, 1);  //放大了10倍数}}                                 //同比例缩放g.drawImage(buff, 0, 0,pixelArr[0].length+220, pixelArr.length+220, null);}/**左转90°*/public int[][] leftPixel(int[][]pixelArr) {//新建数组int [][] newArr = {};//第一次旋转   现在的行是原来列数的最大索引-原来的列    现在的列是原来的行if(flag%4 == 1) {//创建缓冲区对象buff = new  BufferedImage(pixelArr.length, pixelArr[0].length, BufferedImage.TYPE_INT_RGB);//新建数组的大小newArr = new int[pixelArr[0].length][pixelArr.length];for(int i = 0;i < pixelArr.length;i++ ) {for(int j = 0;j < pixelArr[0].length;j++) {newArr[pixelArr[0].length-1-j][i]  =  pixelArr[i][j];}}flag++;}//第二次旋转   现在的行是原来的行   现在的列是原来列的最大索引-列else  if(flag%4 == 2) {buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);newArr = new int[pixelArr.length][pixelArr[0].length];for(int i = 0;i < pixelArr.length;i++) {for(int j = 0;j < pixelArr[0].length;j++) {newArr[i][pixelArr[0].length-1-j] = pixelArr[i][j];}}flag++;}//第三次旋转  现在的行是原来的列   现在的列是原来的行else  if(flag%4 == 3) {buff = new  BufferedImage(pixelArr.length, pixelArr[0].length, BufferedImage.TYPE_INT_RGB);newArr = new int[pixelArr[0].length][pixelArr.length];for(int i = 0;i < pixelArr.length;i++) {for(int j = 0;j < pixelArr[0].length;j++) {newArr[j][i] = pixelArr[i][j];}}flag++;}//第四次旋转else if(flag%4 == 0) {buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);newArr = pixelArr;flag++;}//获取缓冲区的画笔对象Graphics  buffG =  buff.getGraphics();for(int i = 0;i < newArr.length;i++) {for(int j = 0;j < newArr[0].length;j++) {//取出所有的像素值int pixel = newArr[i][j];//把像素值转为Color对象Color color = new Color(pixel);//把缓冲画笔设置成当前颜色buffG.setColor(color);//绘制出当前颜色的像素点buffG.fillRect(j, i, 1, 1);}}g.drawImage(buff,100,100,null);return newArr;}/**右转90°*/public int[][] rightPixel(int[][]pixelArr){//新建数组int [][] newArr = {} ;//第一次旋转  现在的行是原来的列  现在的列是原来行数的最大索引-原来的行if(flag%4 == 1) {//创建缓冲区对象buff = new  BufferedImage(pixelArr.length, pixelArr[0].length, BufferedImage.TYPE_INT_RGB);//新建数组的大小newArr = new int[pixelArr[0].length][pixelArr.length];for(int i = 0;i < pixelArr.length;i++ ) {for(int j = 0;j < pixelArr[0].length;j++) {newArr[j][pixelArr.length-1-i]  =  pixelArr[i][j];}}flag++;}//第二次旋转  现在的行是原来行的最大索引-行   现在的列是原来列的最大索引-列else  if(flag%4 == 2) {buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);newArr = new int[pixelArr.length][pixelArr[0].length];for(int i = 0;i < pixelArr.length;i++) {for(int j = 0;j < pixelArr[0].length;j++) {newArr[pixelArr.length-1-i][pixelArr[0].length-1-j] = pixelArr[i][j];}}flag++;}//第三次旋转       现在的行是原来列的最大索引-列  现在的列是原来的行else  if(flag%4 == 3) {buff = new  BufferedImage(pixelArr.length, pixelArr[0].length, BufferedImage.TYPE_INT_RGB);newArr = new int[pixelArr[0].length][pixelArr.length];for(int i = 0;i < pixelArr.length;i++) {for(int j = 0;j < pixelArr[0].length;j++) {newArr[pixelArr[0].length-1-j][i] = pixelArr[i][j];}}flag++;}//第四次旋转else if(flag%4 == 0) {buff = new  BufferedImage(pixelArr[0].length, pixelArr.length, BufferedImage.TYPE_INT_RGB);newArr = pixelArr;flag++;}//获取缓冲区的画笔对象Graphics  buffG =  buff.getGraphics();//遍历并画出像素点for(int i = 0;i < newArr.length;i++) {for(int j = 0;j < newArr[0].length;j++) {//取出所有的像素值int pixel = newArr[i][j];//把像素值转为Color对象Color color = new Color(pixel);//把缓冲画笔设置成当前颜色buffG.setColor(color);//绘制出当前颜色的像素点buffG.fillRect(j, i, 1, 1);}}g.drawImage(buff, 100, 100, null);return newArr;}}
package com.gch.filterarithmetic;public class Manage {/**主函数*/public static void main(String[] args) {PixelUI ui = new PixelUI();ui.showUI();}
}

四、效果图

Java美颜相机入门(图像处理实现各种滤镜算法)相关推荐

  1. JAVA美颜相机入门(兼具图像处理和画图板功能)

    美颜相机已经成为当代年轻人不可或缺的自拍神器,其具有自动美肌,完美保留细节,让照片告别模糊等功能.或许我们会觉得编写这样一个具有如此强大功能的美颜相机一定需要庞大而且复杂的代码段,其实不然,即使对于初 ...

  2. Java类似相机中图像处理(上)

    Java类似相机中图像处理(上) 一.前情提要 二.项目流程 \qquad 1. 创建窗体 \qquad 2. 动作监听器 \qquad 3. 获取图片文件像素值 \qquad 4. 画原画 \qqu ...

  3. 小浩浅谈之Java美颜相机pc端(视频)

    在之前的文章中,给大家介绍了如果使用WebCamp来使用电脑的摄像头以及如何为图片添加各种滤镜,那么在这我们进行一个相互结合,就构成了一个我们pc端的美颜相机. 1.第一步和之前一样,就是框体 的创建 ...

  4. Java美颜相机(2)图像处理各种滤镜

    利用RGB特性,给图片加上各种滤镜(原图,灰度,二值化,冷色,暖色,怀旧,灵魂出窍(照片底色),铁砂网,美白,放大2倍,乐高,ARGB,画布刷新) 原图 灰度 二值化 随机马赛克 灵魂出窍(照片底色) ...

  5. 深度学习AI美颜系列---AI 发型管家(美颜相机发型管家算法解析)

    美颜相机---AI 发型管家效果的算法解析 ####前言 本文为去年写的Gitchat文章,由于Gitchat有时间版权限制,一年时间,所以今天才能发布到CSDN博客上来. 本文为大家介绍美颜相机中 ...

  6. Android平台美颜相机/Camera实时滤镜/视频编解码/影像后期/人脸技术探索——1.1 工程思路与难点

    回到目录 本文主要探讨搭建一款Android平台下美颜相机可能需要填的坑,内容会不断更新.. 相机框架 相机框架相对比较简单,现有的开源代码很多,可以很容易的实现拍照和录像的功能. 预览尺寸选择 预览 ...

  7. 【项目:实现美颜相机——java】

    我们可以用java代码实现美颜相机的功能. 类似于之前的图片处理效果: [java用监听器实现选择处理图片的效果]_ZERO_HOPE的博客-CSDN博客 摄像头抓取的图片一帧一帧地绘制在界面上,得到 ...

  8. 美颜相机-图片处理(迅速画出+多种滤镜)

    ## 美颜相机 实现美颜相机,我们一共需要三个类 1.UI界面类 2.事件监听器 3.封装方法,直接调用的类 1.UI界面类ImageUI 如果我们一个一个加上按钮会进行大量的复制粘贴工作,所以我们用 ...

  9. android 美颜相机开发,Android OpenGL ES从入门到进阶(一)—— 五分钟开发一款美颜相机...

    源码链接:https://github.com/smzhldr/AGLFramework 一.前言 商店里有数十款的美颜相机类产品,以及像抖音,唱吧之类带有视频的软件,功能很强大,其实现原理基本上都是 ...

最新文章

  1. 4、jquery表格操作
  2. 安装autoit libary失败问题解决
  3. Python 获取项目根路径
  4. 为何外界常说扎克伯格是机器人?源于2018年的一场听证会
  5. 金融危机只是世界统一的第三步
  6. C++基础与深度解析第六章:函数
  7. electronic-wechat高分屏下的缩放修改
  8. 以太坊 solidity return 返回值写法 3种格式
  9. 魅族手机在开发调试中无法打印log的解决方法
  10. QT相关内容的下载链接
  11. 视觉系统设计实例(halcon-winform)-10.PLC通讯
  12. gif动图怎么制作?怎么截取视频做成gif动图?
  13. 教你用Java获取IP归属地
  14. [c++] 使用 raylib + ODE(open dynamics engine) 制作一个简易牛顿摆
  15. win10共享打印机 报错 709 57
  16. 一切就绪,2019年新型智慧城市峰会将展现怎样的“新益阳”
  17. 籍贯怎样填写_籍贯怎么填写才正确(籍贯正确填写方式)
  18. 2016年物联网最后一件大事,GE Predix平台上线-免费试用资格申请
  19. 千姿百态项目经理1——“苦逼”项目经理一
  20. matlab magnify程序,magnifymatlab源程序

热门文章

  1. 第14天 H5页面在微信中如何禁止分享给好友和朋友圈?
  2. ios视频和音频采集
  3. 前端基础 csss3
  4. Mask Scoring R-CNN论文解读
  5. “源”来如此第一期 带你走进开放式协作
  6. 华为校招 C++岗面经(笔试+一面+二面+Offer)
  7. 10.React Native之常量、变量、组件;
  8. 解决在pycharm中使用d2l包(pytorch版)jupyter命令报错的问题
  9. dede集成环境服务器网站设置,Dede织梦CMS服务器环境安全设置
  10. linux 系统的 cache 过大,解决方案