Java实现图像美颜效果

编程入门 行业动态 更新时间:2024-10-26 04:26:57

Java实现图像<a href=https://www.elefans.com/category/jswz/34/1767992.html style=美颜效果"/>

Java实现图像美颜效果

图像原理

对计算机中的一张图片,我们可以将其看成一个宽w*高h的二维数组,即一张图片=int [w][h],在这个二维数组中每个位置对应着一个int值,它们就是这张图片中每个点的像素值,那么我们要对这张图像做处理,实际上就是对这张图片的二维数组进行操作。下面我们首先来实现将原图显示在界面上吧。

实现原图显示

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;import javax.imageio.ImageIO;
import javax.swing.JFrame;public class Image {public static void main(String[] args) {Image image=new Image();image.UI();}public void UI() {JFrame frame=new JFrame("图像处理");frame.setSize(1000,1000);frame.setLocationRelativeTo(null);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setVisible(true);//获取界面的画笔,要放在界面可视之后Graphics g=frame.getGraphics();showImage(g);}public void showImage(Graphics g) {//这里我写的是我放在同包下的一张图片的路径//小伙伴们可以根据实际修改File file=new File("src/img/1.jpg");BufferedImage bi=null;try {bi=ImageIO.read(file);} catch (Exception e) {e.printStackTrace();}int w=bi.getWidth();int h=bi.getHeight();int [][]data=new int[w][h];for(int i=0;i<data.length;i++) {for(int j=0;j<data[i].length;j++) {int v=bi.getRGB(i, j);data[i][j]=v;Color color=new Color(v);g.setColor(color);g.drawLine(i, j, i, j);}}}}

图像基本效果

下面的图像效果介绍,我们尝试去修改上面showImage方法中的循环就可以实现不同的效果啦。

灰度1

for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {Color c = new Color(data[i][j]);int r = c.getRed();int gr = c.getGreen();int b = c.getBlue();int change = (r + gr + b) / 3;c = new Color(change, change, change);g.setColor(c);g.drawLine(i, j, i, j);}}

灰度2

for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {Color c = new Color(data[i][j]);int r = c.getRed();int gr = c.getGreen();int b = c.getBlue();int change = (Math.max(r, Math.max(gr, b)) + Math.min(r, Math.min(gr, b))) / 2;c = new Color(change, change, change);bg.setColor(c);bg.drawLine(i, j, i, j);}}

珠纹化

for (int i = 0; i < data.length; i += 5) {for (int j = 0; j < data[i].length; j += 5) {Color c = new Color(data[i][j]);g.setColor(c);g.fillOval(i, j, 4, 4);}}

油画

for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {Color c = new Color(data[i][j]);g.setColor(c);Random rand = new Random();int k = rand.nextInt(10) + 1;g.fillOval(i, j, k, k);}}

熔铸滤镜

for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {Color c = new Color(data[i][j]);int r = c.getRed();int gr = c.getGreen();int b = c.getBlue();r = r * 128 / (gr + b + 1);gr = gr * 128 / (r + b + 1);b = b * 128 / (r + gr + 1);if (r > 255)r = c.getRed();if (gr > 255)gr = c.getGreen();if (b > 255)b = c.getBlue();c = new Color(r, gr, b);g.setColor(c);g.drawLine(i, j, i, j);}}

去色滤镜

这个效果还不是很理想,如果要做得强大的话,还是要花费时间去做的。

for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {Color c = new Color(data[i][j]);int gr = c.getGreen();if (gr < 52) {g.setColor(c);g.drawLine(i, j, i, j);}}}

马赛克滤镜

for (int i = 0; i < data.length; i += 5) {for (int j = 0; j < data[i].length; j += 5) {Color c = new Color(data[i][j]);g.setColor(c);g.fillRect(i, j, 8, 8);}}

连环画滤镜

for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {Color c = new Color(data[i][j]);int r = c.getRed();int gr = c.getGreen();int b = c.getBlue();r = Math.abs(gr - b + gr + r) * r / 256;gr = Math.abs(b - gr + b + r) * r / 256;b = Math.abs(b - gr + b + r) * gr / 256;if (r < 0 || r > 255)r = c.getRed();if (gr < 0 || gr > 255)gr = c.getGreen();if (b < 0 || b > 255)b = c.getBlue();c = new Color(r, gr, b);g.setColor(c);g.drawLine(i, j, i, j);}}

怀旧滤镜

for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {Color c = new Color(data[i][j]);int r = c.getRed();int gr = c.getGreen();int b = c.getBlue();// 处理溢出r = (int) (0.393 * r + 0.769 * gr + 0.189 * b);gr = (int) (0.349 * r + 0.686 * gr + 0.168 * b);b = (int) (0.272 * r + 0.534 * gr + 0.131 * b);if (r > 255)r = c.getRed();if (gr > 255)gr = c.getGreen();if (b > 255)b = c.getBlue();c = new Color(r, gr, b);g.setColor(c);g.drawLine(i, j, i, j);}}

黑白滤镜

for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {Color c = new Color(data[i][j]);int r = c.getRed();int gr = c.getGreen();int b = c.getBlue();int val = (r + gr + b) / 3;if (val > 80) {g.setColor(Color.white);} else {g.setColor(Color.black);}g.drawLine(i, j, i, j);}}

褐色滤镜

for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {Color c = new Color(data[i][j]);int r = c.getRed();int gr = c.getGreen();int b = c.getBlue();r = (int) (r * 0.393 + gr * 0.769 + b * 0.189);gr = (int) (r * 0.349 + gr * 0.686 + b * 0.168);b = (int) (r * 0.272 + gr * 0.534 + b * 0.131);if (r < 0 || r > 255)r = c.getRed();if (gr < 0 || gr > 255)gr = c.getGreen();if (b < 0 || b > 255)b = c.getBlue();c = new Color(r, gr, b);g.setColor(c);g.drawLine(i, j, i, j);}}

图片合并

	public void showImage(Graphics g) {// 选取两张照片File file1 = new File("src/img/1.jpg");File file2 = new File("src/img/2.jpg");BufferedImage bi = null;BufferedImage bii = null;try {bi = ImageIO.read(file1);bii = ImageIO.read(file2);} catch (Exception e) {e.printStackTrace();}// 取其宽高的最小值,防止数组越界int w = Math.min(bi.getWidth(), bii.getWidth());int h = Math.min(bi.getHeight(), bii.getHeight());// 创建一块与打开的图片一样大小的缓冲区bi_img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);// 获取缓冲区的画笔bg = bi_img.getGraphics();for (int i = 0; i < w; i++) {for (int j = 0; j < h; j++) {int v1 = bi.getRGB(i, j);int v2 = bii.getRGB(i, j);Color color1 = new Color(v1);Color color2=new Color(v2);// 在缓冲区中绘制图像的每个像素点int r=(int)(color1.getRed()*0.7+color2.getRed()*0.3);int gr=(int)(color1.getGreen()*0.3+color2.getGreen()*0.7);int b=(int)(color1.getBlue()*0.3+color2.getBlue()*0.7);Color color=new Color(r,gr,b);bg.setColor(color);bg.drawLine(i, j, i, j);}}// 缓冲区绘制完成后,用界面的画笔一次性将图像画出来g.drawImage(bi_img, 0, 0, bi_img.getWidth(), bi_img.getHeight(), null);}

负片

for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {Color c = new Color(-data[i][j]);g.setColor(c);g.drawLine(i, j, i, j);}}

反向滤镜

for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {Color c = new Color(data[i][j]);int r = c.getRed();int gr = c.getGreen();int b = c.getBlue();r = 255 - r;gr = 255 - gr;b = 255 - b;c = new Color(r, gr, b);g.setColor(c);g.drawLine(i, j, i, j);}}

冰冻滤镜

for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {Color c = new Color(data[i][j]);int r = c.getRed();int gr = c.getGreen();int b = c.getBlue();r = (r - gr - b) * 3 / 2;gr = (gr - r - b) * 3 / 2;b = (b - r - gr) * 3 / 2;if (r < 0 || r > 255)r = c.getRed();if (gr < 0 || gr > 255)gr = c.getGreen();if (b < 0 || b > 255)b = c.getBlue();c = new Color(r, gr, b);g.setColor(c);g.drawLine(i, j, i, j);}}

单色滤镜

红色
for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {Color color = new Color(data[i][j]);int r = color.getRed();color = new Color(r, 0, 0);g.setColor(color);g.drawLine(i, j, i, j);}}
绿色

for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {Color color = new Color(data[i][j]);int gr = color.getGreen();color = new Color(0, gr, 0);g.setColor(color);g.drawLine(i, j, i, j);}}
蓝色

for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {Color color = new Color(data[i][j]);int b = color.getBlue();color = new Color(0, 0, b);g.setColor(color);g.drawLine(i, j, i, j);}}

优化图像显示

图像缓冲区

计算机当中设备的速度大体上可以分为CPU、内存、IO设备三类(其实CPU与内存之间还有cache,但在这里并不影响解释这个问题),它们的速度由快到慢,也就是说IO设备在计算机中属于低速设备,与IO设备进行交互的话将会花费大量时间。而我们上面的写法都是将图像中的每个像素点依次去画在界面上,当图像过大的时候,显示在界面上就会需要等待一定的响应时间。但是现在我们首先在缓冲区中将图像绘制下来,在缓冲区中图像绘制完成以后,再一次性将图像在界面上画出来就好了,那么原来需要与IO设备交互w*h次,现在就只需要交互一次就够了,性能上就会有显著提升。我们还是以显示原图为例来演示缓冲区的使用。

使用缓冲区显示原图

	public void showImage(Graphics g) {//这里我写的是我放在同包下的一张图片的路径//小伙伴们可以根据实际修改File file=new File("src/img/1.jpg");BufferedImage bi=null;	try {bi=ImageIO.read(file);} catch (Exception e) {e.printStackTrace();}int w=bi.getWidth();int h=bi.getHeight();//创建一块与打开的图片一样大小的缓冲区BufferedImage bi_img=new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);//获取缓冲区的画笔Graphics bg=bi_img.getGraphics();int [][]data=new int[w][h];for(int i=0;i<data.length;i++) {for(int j=0;j<data[i].length;j++) {int v=bi.getRGB(i, j);data[i][j]=v;Color color=new Color(v);//在缓冲区中绘制图像的每个像素点bg.setColor(color);bg.drawLine(i, j, i, j);}}//缓冲区绘制完成后,用界面的画笔一次性将图像画出来g.drawImage(bi_img, 0, 0, bi_img.getWidth(), bi_img.getHeight(), null);}

文件选择器

我们的代码写的图片路径都是直接固定的,那在不同的电脑上可能不会存在这样的路径或者图片,那么我们这时候可以提供一个对话框来供用户选择图片,然后对选择的图片做处理这样子。

文件选择器代码示例

我们通过下面的测试openFile方法已经可以成功返回我们在电脑上选择图片的绝对路径,那么我们只需要对上面的showImage方法的参数添加一个String类的参数,然后将new File的路径改成这个String类的参数就可以了。

public class Image {public static void main(String[] args) {Image image=new Image();System.out.println(image.openFile());}public String openFile() {JFileChooser chooser=new JFileChooser();// 文件选择器添加过滤FileNameExtensionFilter filter=new FileNameExtensionFilter("Image files", "jpg");chooser.setFileFilter(filter);// 显示(打开文件)的选择器int returnVal=chooser.showOpenDialog(null);// 判断返回值if(returnVal==JFileChooser.APPROVE_OPTION) {// 获取选择的文件File file=chooser.getSelectedFile();// 返回文件的绝对路径return file.getAbsolutePath();}// 没有选择文件的情况return "";}

图像重绘

最后的一个小优化就是,当我们拖动界面或者将窗体改变大小时,界面上的图像就会消失,那么这时候我们就要继承JFrame并且重写paint方法,让窗体发生改变时,我们的界面重新绘制图像。paint方法并不需要我们定义何时调用,我们只需要在里面写代码规定窗体改变时(会自动调用paint方法)需要重绘的内容即可。所以我们的UI方法也有些许改变,而且为了方便我的重绘操作,我将缓冲区与缓冲区的画笔设置成了全局的变量。所以,我这里就再贴了一次有点相似的代码。

图像重绘代码示例

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;import javax.imageio.ImageIO;
import javax.swing.JFrame;public class Image extends JFrame{BufferedImage bi_img=null;Graphics bg=null;public static void main(String[] args) {Image image=new Image();image.UI();}public void UI() {this.setTitle("图像处理");this.setSize(1000,1000);this.setLocationRelativeTo(null);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setVisible(true);//获取界面的画笔,要放在界面可视之后Graphics g=this.getGraphics();showImage(g);}public void showImage(Graphics g) {//这里我写的是我放在同包下的一张图片的路径//小伙伴们可以根据实际修改File file=new File("src/img/1.jpg");BufferedImage bi=null;	try {bi=ImageIO.read(file);} catch (Exception e) {e.printStackTrace();}int w=bi.getWidth();int h=bi.getHeight();//创建一块与打开的图片一样大小的缓冲区bi_img=new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);//获取缓冲区的画笔bg=bi_img.getGraphics();int [][]data=new int[w][h];for(int i=0;i<data.length;i++) {for(int j=0;j<data[i].length;j++) {int v=bi.getRGB(i, j);data[i][j]=v;Color color=new Color(v);//在缓冲区中绘制图像的每个像素点bg.setColor(color);bg.drawLine(i, j, i, j);}}//缓冲区绘制完成后,用界面的画笔一次性将图像画出来g.drawImage(bi_img, 0, 0, bi_img.getWidth(), bi_img.getHeight(), null);}public void paint(Graphics g) {super.paint(g);if(bi_img!=null)g.drawImage(bi_img, 0, 0, bi_img.getWidth(), bi_img.getHeight(), null);}}

更多推荐

Java实现图像美颜效果

本文发布于:2024-03-09 07:36:41,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1724317.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:美颜   图像   效果   Java

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!