您的位置:首页 > 科技 > 能源 > 美颜相机java

美颜相机java

2024/9/29 20:00:23 来源:https://blog.csdn.net/2301_79636742/article/details/141534933  浏览:    关键词:美颜相机java

马赛克实现:

代码会遍历图像的像素,根据一定的块大小,将每个块的像素颜色平均化或设置为块中某个像素的颜色,从而实现马赛克效果。

    public void mosaic() {bufferZone();int x = s;// 代码会遍历图像的像素,根据一定的块大小,将每个块的像素颜色平均化或设置为块中某个像素的颜色,从而实现马赛克效果。int[][] data = image(fn);for (int i = 0; i < data.length; i += (15+1.6*x)) {for (int j = 0; j < data[i].length; j += (15+1.6*x)) {Color color = new Color(data[i][j]);bg.setColor(color);bg.fillRect(i / 2, j/ 2, 15, 15);// 在绘图缓冲区绘制一个矩形,模拟马赛克效果}}//把缓冲区显示在窗体;g.drawImage(bufferedImage,0,22,j1);}

灰度: 

计算红绿蓝三个颜色通道的平均值作为灰度值,画笔调成该颜色再去绘制像素点

public void grey(){bufferZone();int[][] data = image(fn);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 red = color.getRed();int green = color.getGreen();int blue = color.getBlue();int sum = (red+green+blue)/3;// 计算红绿蓝三个颜色通道的平均值作为灰度值,用该颜色绘制像素点Color newColor = new Color(sum,sum,sum);bg.setColor(newColor);//画笔颜色bg.drawOval(i/2,j/2,1,1);//像素点}}//把缓冲区显示在窗体;g.drawImage(bufferedImage,0,22,j1);}

 画原图

    public void oripic(){//通过bufferZone方法创建图像的缓冲区,然后遍历图像的每个像素点,使用fillOval画出每个像素bufferZone();// 准备绘图环境int[][] data = image(fn);//图片放在项目目录下for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {//得到颜色值,画出每一个点Color c = new Color(data[i][j]);bg.setColor(c);//画笔颜色bg.fillOval(i / 2, j /2, 2, 2);//像素点}}//把缓冲区显示在窗体;g.drawImage(bufferedImage,0,22,j1);}

 二值化:

设定一个阀值,超过的黑色,没过的白色,从而就黑白,即实现二值化

    public void binarization() {bufferZone();int x = s;// 定义二值化处理的阈值调整因子int[][] data = image(fn);int h = data.length;int w = data[0].length;for(int i = 0; i < h; i++){for(int j = 0; j < w; j++){int p = data[i][j];// 获取当前像素的颜色值Color color = new Color(p);// 根据颜色值创建颜色对象int blue = color.getBlue();if (blue >(70+2*x)){   // 根据蓝色分量与阈值的比较结果设置画笔颜色bg.setColor(Color.BLACK);}else{bg.setColor(Color.WHITE);}bg.drawOval(i/2,j/2,1,1);}}//把缓冲区显示在窗体;g.drawImage(bufferedImage,0,22,j1);}

放大: 

遍历每个像素点,并在原位置周围绘制更大的矩形,实现放大效果。

    public void Todouble(){//遍历每个像素点,并在原位置周围绘制更大的矩形,实现放大效果。bufferZone();int x = s;int[][] data = image(fn);//图片放在项目目录下for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {//得到颜色值,画出每一个点Color c = new Color(data[i][j]);bg.setColor(c);// 绘制一个矩形,实现图像的放大效果bg.fillRect(i*(x/2)/2, j *(x/2)/2, x, x);}}g.drawImage(bufferedImage, 0, 22, j1);}

缩小:

放大同理

    public void narrow(){bufferZone();int x = s;// 定义缩放因子int[][] data = image(fn);//图片放在项目目录下int w= data.length;int h=data[0].length;for (int i = 0; i < w; i+=2) {for (int j = 0; j < h; j+=2) {//得到颜色值,画出每一个点Color c = new Color(data[i][j]);bg.setColor(c);// 绘制一个矩形,宽度和高度为x,实现缩放效果bg.fillRect(i/(2*x) , j/(2*x), x, x);//通过每隔一定数量的像素点取一个像素,并在缩小后的图像上绘制相应的像素,实现缩小效果。}}g.drawImage(bufferedImage, 0, 22, j1);}

油画效果

在我看来就是把马赛克的划分像素再小一点,实现油彩笔拖动画画的效果 

 

    public void oil(){bufferZone();int x = s;int[][] data = image(fn);for (int i =0; i < data.length-5; i +=5){// 遍历图像,跳过一定数量的像素点以模拟油画的笔触for (int j =0; j < data[i].length-5; j +=5) {Color color = new Color(data[i][j]);bg.setColor(color);Random ran=new Random();// 生成随机大小的椭圆,模拟油画的笔触效果int r1 = ran.nextInt(20)*x+5;int r2 = ran.nextInt(40)*x+5;bg.fillOval((i+x)/2, (j+x)/2,Math.max(r1,r2), Math.min(r1,r2));}}//把缓冲区显示在窗体;g.drawImage(bufferedImage,0,22,j1);}

哈哈镜:

根据鼠标点击的位置,计算每个像素点相对于点击点的距离和角度,然后根据这些值调整像素点的新位置

    public void funhouseMirror() {//根据鼠标点击的位置,计算每个像素点相对于点击点的距离和角度,然后根据这些值调整像素点的新位置bufferZone();int x = s;int[][] data = image(fn);int h=data.length;int w=data[0].length;int maxDist = (int) Math.sqrt((w/2 - a) * (w/2 - a) + (h/2 - b) * (h/2 - b));for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {int deltaX = i - b;int deltaY = j - a;double distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);int newX = (int) (i + deltaX * x * maxDist / distance*0.1);int newY = (int) (j + deltaY * x * maxDist / distance*0.1);if (newX >= 0 && newX < data.length && newY >= 0 && newY < data[i].length) {Color color = new Color(data[newX][newY]);bg.setColor(color);bg.drawOval(i/2, j/2, 1, 1);}}}// 把缓冲区显示在窗体;g.drawImage(bufferedImage, 0, 22, j1);}

这里解释一下:

计算位移量: deltaX * x * maxDist / distance * 0.1 和 deltaY * x * maxDist / distance * 0.1 计算了像素应移动的距离。

比例因子: (maxDist / distance) 用于调整移动量,使得离点击点更远的像素点移动更多。这样就实现了拉伸效果。

远离点击点的像素:对于离点击点更远的像素,distance 较大,但 (maxDist / distance) 比例较小;然而,由于 deltaX 和 deltaY 的值较大,这些像素点的移动幅度仍然会很大。
靠近点击点的像素:对于离点击点更近的像素,distance 较小,而 (maxDist / distance) 比例较大,但由于 deltaX 和 deltaY 的值较小,这些像素点的移动幅度较小。
放大或缩小: 由于公式中乘以了 x 和 0.1,拉伸或压缩效果可以被调节。

当 x 增大时,拉伸效果会变得更显著。
当 x 减小时(接近于0),拉伸效果会减少,直到完全没有变形

加密

就是输入的askII添加到蓝色阈的最后两位

最后附上源码

package meiyan0811complete;
import javax.imageio.ImageIO;//用于读取和写入图片
import javax.swing.*;//构建图形用户界面
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;
import java.util.Random;
import java.util.Scanner;public class DrawMouse implements ActionListener,MouseListener {public Graphics g;// 绘制图形private Graphics bg;//背景绘制private BufferedImage bufferedImage;public String str;//存储按钮点击事件的字符串public JPanel j1=null;public int s=1 ;//用于存储滑动条的值,默认为1public int a,b;// 鼠标点击位置的x,y坐标public String fn = "D:\\桌面\\11.jpg";public void mouseClicked(MouseEvent e){int x =a= e.getX();int y =b= e.getY();}public void mousePressed(MouseEvent e){}public void mouseReleased(MouseEvent e){}public void mouseEntered(MouseEvent e){}public void mouseExited(MouseEvent e){}public void actionPerformed(ActionEvent e) {//处理按钮点击String btnStr = e.getActionCommand();//获取输入的命令str = btnStr;System.out.println("用户点击了" + btnStr+"按钮......");System.out.println("稍等一会,图片效果马上呈现");// 使用SwingWorker来执行异步图像处理,是Java Swing库中的一个类// 它提供了一种在后台线程中执行长时间运行的任务并更新Swing用户界面的方法。SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {protected Void doInBackground() {// 根据按钮选择的效果处理图像//根据字符串绘制相关图片switch (btnStr) {case "原图":oripic();break;case "灰度"://取rgb平均值,则画成灰度图grey();break;case "二值化":binarization();break;case "马赛克":mosaic();break;case"放大":Todouble();break;case"缩小":narrow();break;case"油画":oil();break;case"哈哈镜":funhouseMirror();break;case "旋转":spin();break;case "加密":encrypt();break;}return null;}protected void done() {g.drawImage(bufferedImage, 0, 22, j1);// 将处理后的图像绘制到JPanel上}};worker.execute();//启动一个后台任务,该任务在 doInBackground() 中执行图像处理,完成后在 done() 中更新UI}//程序的执行过程:代码 > jvm > os > 总线 > 显示器//创建缓冲区 把所有的像素点显示在缓存去上public void bufferZone() {int[][] data = image(fn);// 将图片文件转换为int型的二维数组bufferedImage = new BufferedImage( data.length, data[0].length,BufferedImage.TYPE_INT_RGB);bg = bufferedImage.getGraphics();bg.setColor(Color.WHITE);bg.fillRect(0,0,bufferedImage.getWidth(),bufferedImage.getHeight());}public void oripic(){//通过bufferZone方法创建图像的缓冲区,然后遍历图像的每个像素点,使用fillOval画出每个像素bufferZone();// 准备绘图环境int[][] data = image(fn);//图片放在项目目录下for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {//得到颜色值,画出每一个点Color c = new Color(data[i][j]);bg.setColor(c);//画笔颜色bg.fillOval(i / 2, j /2, 2, 2);//像素点}}//把缓冲区显示在窗体;g.drawImage(bufferedImage,0,22,j1);}public void grey(){bufferZone();int[][] data = image(fn);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 red = color.getRed();int green = color.getGreen();int blue = color.getBlue();int sum = (red+green+blue)/3;// 计算红绿蓝三个颜色通道的平均值作为灰度值,用该颜色绘制像素点Color newColor = new Color(sum,sum,sum);bg.setColor(newColor);//画笔颜色bg.drawOval(i/2,j/2,1,1);//像素点}}//把缓冲区显示在窗体;g.drawImage(bufferedImage,0,22,j1);}public void mosaic() {bufferZone();int x = s;// 代码会遍历图像的像素,根据一定的块大小,将每个块的像素颜色平均化或设置为块中某个像素的颜色,从而实现马赛克效果。int[][] data = image(fn);for (int i = 0; i < data.length; i += (15+1.6*x)) {for (int j = 0; j < data[i].length; j += (15+1.6*x)) {Color color = new Color(data[i][j]);bg.setColor(color);bg.fillRect(i / 2, j/ 2, 15, 15);// 在绘图缓冲区绘制一个矩形,模拟马赛克效果}}//把缓冲区显示在窗体;g.drawImage(bufferedImage,0,22,j1);}public void binarization() {bufferZone();int x = s;// 定义二值化处理的阈值调整因子int[][] data = image(fn);int h = data.length;int w = data[0].length;for(int i = 0; i < h; i++){for(int j = 0; j < w; j++){int p = data[i][j];// 获取当前像素的颜色值Color color = new Color(p);// 根据颜色值创建颜色对象int blue = color.getBlue();if (blue >(70+2*x)){   // 根据蓝色分量与阈值的比较结果设置画笔颜色bg.setColor(Color.BLACK);}else{bg.setColor(Color.WHITE);}bg.drawOval(i/2,j/2,1,1);}}//把缓冲区显示在窗体;g.drawImage(bufferedImage,0,22,j1);}public void narrow(){bufferZone();int x = s;// 定义缩放因子int[][] data = image(fn);//图片放在项目目录下int w= data.length;int h=data[0].length;for (int i = 0; i < w; i+=2) {for (int j = 0; j < h; j+=2) {//得到颜色值,画出每一个点Color c = new Color(data[i][j]);bg.setColor(c);// 绘制一个矩形,宽度和高度为x,实现缩放效果bg.fillRect(i/(2*x) , j/(2*x), x, x);//通过每隔一定数量的像素点取一个像素,并在缩小后的图像上绘制相应的像素,实现缩小效果。}}g.drawImage(bufferedImage, 0, 22, j1);}public void Todouble(){//遍历每个像素点,并在原位置周围绘制更大的矩形,实现放大效果。bufferZone();int x = s;int[][] data = image(fn);//图片放在项目目录下for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {//得到颜色值,画出每一个点Color c = new Color(data[i][j]);bg.setColor(c);// 绘制一个矩形,实现图像的放大效果bg.fillRect(i*(x/2)/2, j *(x/2)/2, x, x);}}g.drawImage(bufferedImage, 0, 22, j1);}public void oil(){bufferZone();int x = s;int[][] data = image(fn);for (int i =0; i < data.length-5; i +=5){// 遍历图像,跳过一定数量的像素点以模拟油画的笔触for (int j =0; j < data[i].length-5; j +=5) {Color color = new Color(data[i][j]);bg.setColor(color);Random ran=new Random();// 生成随机大小的椭圆,模拟油画的笔触效果int r1 = ran.nextInt(20)*x+5;int r2 = ran.nextInt(40)*x+5;bg.fillOval((i+x)/2, (j+x)/2,Math.max(r1,r2), Math.min(r1,r2));}}//把缓冲区显示在窗体;g.drawImage(bufferedImage,0,22,j1);}public void funhouseMirror() {//根据鼠标点击的位置,计算每个像素点相对于点击点的距离和角度,然后根据这些值调整像素点的新位置bufferZone();int x = s;int[][] data = image(fn);int h=data.length;int w=data[0].length;int maxDist = (int) Math.sqrt((w/2 - a) * (w/2 - a) + (h/2 - b) * (h/2 - b));for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {int deltaX = i - b;int deltaY = j - a;double distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);int newX = (int) (i + deltaX * x * maxDist / distance*0.1);int newY = (int) (j + deltaY * x * maxDist / distance*0.1);if (newX >= 0 && newX < data.length && newY >= 0 && newY < data[i].length) {Color color = new Color(data[newX][newY]);bg.setColor(color);bg.drawOval(i/2, j/2, 1, 1);}}}// 把缓冲区显示在窗体;g.drawImage(bufferedImage, 0, 22, j1);}//对于每个字符的信息,程序会获取其ASCII码值,并且将这个值的最低两位与蓝色分量的最低两位进行位运算,从而隐藏信息。//遍历每个像素点,将输入的文本信息的ASCII码值隐藏在像素点的蓝色通道的最低2位,然后使用修改后的颜色值绘制像素点。public void encrypt(){bufferZone();int[][] data = image(fn);System.out.println("请输入所要加入图像里的信息:");Scanner scanner = new Scanner(System.in);String messageToEncrypt = scanner.nextLine();scanner.close();int messageIndex = 0;for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {if (messageIndex < messageToEncrypt.length()) {Color color = new Color(data[i][j]);int red = color.getRed();int green = color.getGreen();int blue = color.getBlue();char charToHide = messageToEncrypt.charAt(messageIndex);int asciiValue = (int) charToHide;// 将ASCII码值存储到蓝色通道的最低2位blue = (blue & 0xFC) | ((asciiValue >> 6) & 0x03);Color newColor = new Color(red, green, blue);bg.setColor(newColor);bg.drawOval(i / 2, j / 2, 1, 1);messageIndex++;} else {// 如果已经加密完整个信息,则将原图像像素写入缓冲区Color color = new Color(data[i][j]);bg.setColor(color);bg.drawOval(i / 2, j / 2, 1, 1);}}}// 把缓冲区显示在窗体;g.drawImage(bufferedImage, 0, 22, j1);try {File outputImageFile = new File("encrypted_image.jpg"); // 新文件的路径ImageIO.write(bufferedImage, "jpg", outputImageFile);System.out.println("加密后的图像已保存到文件 'encrypted_image.jpg'");} catch (IOException e) {System.out.println("保存图像文件时出现错误: " + e.getMessage());}}public void spin(){bufferZone();int x = s;int[][] data = image(fn);}//将一张图片转化一个int型的二维数组private int[][] image(String imageName) {File file = new File(fn);BufferedImage bi = null;try {bi = ImageIO.read(file); //从文件到图片对象} catch (Exception e) {//catch块用于捕获并处理try块中抛出的任何异常。这里的Exception e表示捕获所有类型的异常e.printStackTrace();}int w = bi.getWidth(); //图片的宽int h = bi.getHeight(); //图片的高int[][] imIndex = new int[w][h];//存像素值的二维数组for (int i = 0; i < w; i++) {for (int j = 0; j < h; j++) {imIndex[i][j] = bi.getRGB(i, j); //i,j 位置的 Color 值,每个像素点的 color 存入数组}}return imIndex;}
}

package meiyan0811complete;import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;public class ImageBoard  extends  JFrame {//private  DrawMouse dl=null;String fName;DrawMouse mouse = new DrawMouse();public void initUI() {//窗体的创建this.setTitle("PC版美颜相机--by 张宇超");this.setSize(1000, 600);this.getContentPane().setBackground(Color.WHITE);this.setDefaultCloseOperation(3);this.setLocationRelativeTo(null);this.setLayout(new BorderLayout());//按钮面板  对象JPanel  默认是流式布局JPanel eastPanel = new JPanel();eastPanel.setBackground(new Color(220,226,248));eastPanel.setPreferredSize(new Dimension(200,0));this.add(eastPanel,BorderLayout.EAST);//图画面板JPanel drawPanel = new JPanel();drawPanel.setBackground(Color.WHITE);drawPanel.setPreferredSize(new Dimension(800,500));this.add(drawPanel,BorderLayout.CENTER);mouse.j1=drawPanel;drawPanel.addMouseListener(mouse);this.setVisible(true);Graphics g=drawPanel.getGraphics();mouse.g = g;String[] strs={"原图","二值化","灰度","马赛克","放大","缩小","油画","哈哈镜","旋转","加密"};Color primaryColor = new Color(137, 190, 178);Color textColor = Color.WHITE;// 应用颜色方案到按钮Font buttonFont = new Font("宋体", Font.PLAIN, 16); // 设置按钮字体和字号for(int i=0;i< strs.length;i++) {JButton buDraw = new JButton(strs[i]); // 对于字符串数组strs中的每一个字符串,创建一个新的JButton对象。buDraw.setPreferredSize(new Dimension(80,30));//按钮大小buDraw.setBackground(primaryColor);//背景颜色buDraw.setForeground(textColor);//按钮前景颜色buDraw.setFont(buttonFont);//应用字体buDraw.setBorder(BorderFactory.createEmptyBorder(5, 15, 5, 15));//创建一个空白边框,为按钮的内容留出一些空间,使其看起来更加整洁和美观。eastPanel.add(buDraw);//按钮添加到面板里buDraw.addActionListener(mouse);//动作监听器}JLabel j1 = new JLabel("大小/程度选择:");//显示文本的labelj1.setFont(new Font("黑体",1,15));eastPanel.add(j1);JMenuBar jmb = new JMenuBar();//菜单栏JMenu jm = new JMenu();//菜单栏里面的菜单项jm.setText("文件");jmb.add(jm);this.setJMenuBar(jmb);JMenuItem open = new JMenuItem();//菜单项open.setText("Open");jm.add(open);//按钮键->按钮功能(动作监听器)open.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {if(e != null){JFileChooser jfc =new JFileChooser();jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);//创建文件选择器jfc.showDialog(new Label(),"选中");File file = jfc.getSelectedFile();fName = file.getPath();mouse.fn = fName;}}});//拉杆,滑动条可能用于控制图像处理的强度、大小或其他可调节的参数JSlider js1 = new JSlider(1,10);// 创建一个滑动条,范围从1到10js1.setMajorTickSpacing(1);// 设置主刻度之间的间距为1。js1.setMinorTickSpacing(1);// 设置次刻度之间的间距为1。js1.setPreferredSize(new Dimension(200,80));js1.setFont (new Font ("黑体",1,15));js1.setPaintLabels(true);js1.setPaintTicks(true);js1.setSnapToTicks(true);js1.setOpaque(false);js1.setValue(1);eastPanel.add(js1);js1.addChangeListener(new ChangeListener() {public void stateChanged(ChangeEvent e) {g.setColor(Color.WHITE);g.fillRect(0,100,1000,1000);if(e != null){int x =js1.getValue();mouse.s = x;}}});}public void paint(Graphics g) {super.paint(g);if (mouse.fn != null){switch (mouse.str){case "原图":mouse.oripic();break;case "灰度":mouse.grey();break;case "二值化":mouse.binarization();break;case "马赛克":mouse.mosaic();break;case "放大":mouse.Todouble();break;case "缩小":mouse.narrow();break;case "油画":mouse.oil();break;case"哈哈镜":mouse.funhouseMirror();break;case"旋转":mouse.spin();break;case"加密":mouse.encrypt();break;default:break;}}}public static void main(String[] args) {new ImageBoard().initUI();}}
注释也很详细

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com