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

一、思路分析

一款简易美颜相机的功能我们可以简单分为两大块:一是对拍摄出的照片可以进行马赛克,美白,灰度调整等功能;二是可以在照片上画圆圈,画直线等涂鸦功能。因此,我们在写代码时,把需要实现的功能分成如下两部分:

1、图像处理

2、画板

下面先展示本次完工后美颜相机的效果图:

二、代码分析

这边先只分析重要部分代码,最终的完整代码附在文章末尾!

和前面我们做五子棋游戏类似,在实现美颜相机功能的第一步还是先画界面,首先,我们需要画一个类似于 P 图软件的界面,上面拥有照片处理涂鸦区,按钮区,颜色选择区,菜单等功能区,因此先 new 一个 DrawUI 类(当然也可以取其他名字),在这个类中,我们首先把界面画出来,为了方便管理,我们设置了一个菜单和三个 JPanel,一个 JPanel 里放 ImagePanel,用于照片处理和涂鸦,另两个 Panel 里放相关功能按钮。

    public void initUI(){JFrame jf = new JFrame();jf.setSize(1400,900);jf.setTitle("PC版美颜相机");jf.setLocationRelativeTo(null);jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setVisible(true);JPanel[] jps = addPanel(jf);addButton(jps);addJSlider(jps);addMenu(jf);}

添加界面上的 JPanel :

private JPanel[] addPanel(JFrame jf) {JPanel[] jps = new JPanel[3];String[] layoustrs = {BorderLayout.CENTER,BorderLayout.SOUTH,BorderLayout.EAST};imgPanel.setBackground(Color.LIGHT_GRAY);imgPanel.addMouseListener(ul);jf.add(imgPanel,layoustrs[0]);jps[0] = imgPanel;Dimension dim = new Dimension(320,100);JPanel jp_s1 = new JPanel();jp_s1.setBackground(Color.ORANGE);jp_s1.setPreferredSize(dim);jf.add(jp_s1,layoustrs[1]);jps[1] = jp_s1;JPanel jp_s2 = new JPanel();jp_s2.setBackground(Color.YELLOW);jp_s2.setPreferredSize(dim);jf.add(jp_s2,layoustrs[2]);jps[2] = jp_s2;return jps;}

添加界面上的按钮:

private void addButton(JPanel[] jps) {String[] btnstrs1 = new String[]{"原图","撤回","马赛克","灰度","轮廓","二值化","油画","美白","运动模糊","卷积","锐化","浮雕","左旋","右旋","放大","缩小","打开摄像头","关闭摄像头"};for(int i = 0; i < btnstrs1.length-2; i++){JButton btn = new JButton(btnstrs1[i]);Dimension dim = new Dimension(120,40);btn.setPreferredSize(dim);btn.setFont(new Font("黑体",1,20));btn.setBackground(Color.WHITE);btn.addActionListener(ul);jps[2].add(btn);}for(int i = btnstrs1.length-2; i < btnstrs1.length; i++){JButton btn = new JButton(btnstrs1[i]);Dimension dim = new Dimension(200,40);btn.setPreferredSize(dim);btn.setFont(new Font("黑体",1,20));btn.setBackground(Color.WHITE);btn.addActionListener(ul);jps[2].add(btn);}String[] btnstrs2 = new String[] {"直线","矩形","椭圆","三角形","正方形","菱形","特殊三角形","多边形","画点","迭代","树"};for(int i = 0; i < btnstrs2.length; i++) {JButton btn = new JButton(btnstrs2[i]);Dimension dim = new Dimension(120,40);btn.setPreferredSize (dim);btn.setFont (new Font ("黑体",1,16));btn.setBackground (Color.WHITE);btn.addActionListener (ul);jps[1].add (btn);}Color []color= {Color.BLUE,Color.GREEN,Color.YELLOW,Color.BLACK,Color.ORANGE,Color.GRAY,Color.RED};for(int i=0;i<color.length;i++) {JButton jbui=new JButton();jbui.setBackground(color[i]);Dimension dmi=new Dimension(40,40);jbui.setPreferredSize(dmi);jbui.addActionListener(ul);jps[1].add(jbui);}}

添加界面上的滑动条:

private void addJSlider(JPanel[] jps) {JLabel j0 = new JLabel("                                                ");j0.setFont(new Font("黑体",1,30));jps[2].add(j0);JLabel j1 = new JLabel("大小/程度选择:");j1.setFont(new Font("黑体",1,30));jps[2].add(j1);JSlider jSlider = new JSlider(0,100);Dimension dm = new Dimension(300,80);  //设置按钮尺寸jSlider.setPreferredSize (dm);jSlider.setFont (new Font ("黑体",1,15));jSlider.setMajorTickSpacing(20);jSlider.setMinorTickSpacing(5);jSlider.setPaintLabels(true);//确定是否在滑块上绘制标签jSlider.setPaintTicks(true);//确定是否在滑块上绘制刻度标记jSlider.setPaintTrack(true);//确定是否在滑块上绘制滑道jSlider.setSnapToTicks(true);//指定为 true,则滑块(及其所表示的值)解析为最靠近用户放置滑块处的刻度标记的值jSlider.setOpaque(false);jps[2].add(jSlider);jSlider.addChangeListener(new ChangeListener() {@Overridepublic void stateChanged(ChangeEvent e) {System.out.println("当前值: " + jSlider.getValue());int p = jSlider.getValue();iu.p = p;}});}

添加界面上的菜单:

private void addMenu(JFrame jf) {//菜单栏JMenuBar jmb = new JMenuBar();jf.add(jmb,BorderLayout.NORTH);//菜单选项JMenu file = new JMenu("文件");file.setPreferredSize(new Dimension(80,40));file.setFont(new Font("宋体",2,22));jmb.add(file);//子菜单JMenuItem jmi1 = new JMenuItem("打开");jmi1.setPreferredSize(new Dimension(80,40));jmi1.setFont(new Font("宋体",2,22));jmi1.addActionListener(ul);file.add(jmi1);JMenuItem jmi2 = new JMenuItem("保存");jmi2.setPreferredSize(new Dimension(80,40));jmi2.setFont(new Font("宋体",2,22));jmi2.addActionListener(ul);file.add(jmi2);jf.setVisible(true);}

界面画完后就涉及到图像处理部分了,根据事先设定好的路径把图片的像素读进 imgArray[ ][ ] 数组中,后期根据需要对数组中每一个位置的值进行相应的处理变换就可以获得处理后的图像啦!代码中,width 是我们读取到的图像的宽度,height 是我们读取到的图像的高度,后面我们又设定了 width0 和 height0 的值,他们都等于图像宽度和高度中的较大者,其实, width0 和 height0 的值是我们定义的画布的宽度和高度,因为我们后面会用到图像旋转功能,所以画布的尺寸边长应为图像宽度和高度值中的较大者,(如果画布尺寸和图像尺寸一样,那么在旋转的过程中可能图像会显示不全)。

public int[][] readImagePix(String path){// 文件对象File file = new File (path);BufferedImage readimg = null;try {readimg = ImageIO.read (file);} catch (IOException e) {e.printStackTrace ();}int width = readimg.getWidth ();int height = readimg.getHeight ();int height0 = 0;int width0 = 0;if(width >= height){height0 = width;width0 = width;}if(width < height){width0 = height;height0 = height;}imgPanel.width = width;imgPanel.height= height;int[][] imgArray = new int[width0][height0];for(int i = 0; i < width; i++){for(int j = 0; j < height; j++){imgArray[i][j] = readimg.getRGB (i, j);}}return imgArray;}

为了后面处理图像方便,我们先写了一个获取灰度值的函数:

public int getRgbGray(int numPixels){// byte -128 127int red = (numPixels>>16)&0xFF;int green = (numPixels>>8)&255;int blue = (numPixels>>0)&255;// 灰度 -- 减少计算量 以及 更方便计算int gray = (red + green + blue) / 3;return gray;}

下面介绍几种图像处理的方法,第一个是原图,原图应该是最简单的部分了,我们只需要根据数组 imgArray[ ][ ] 把每一个位置的像素画出来就好。

public BufferedImage drawImage_00(int[][] imgArray){BufferedImage buffimg = new BufferedImage ( imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);for(int i = 0; i < imgArray.length; i++){for(int j = 0; j < imgArray[i].length; j++){buffimg.setRGB (i,j,imgArray[i][j]);}}return buffimg;}

马赛克就是在图像上每隔一定的距离画一个方块,该方块的颜色和方块中心的颜色一样,当然也可以取方块中所有像素的平均值,这边需要注意的是,图像的长度并不一定是方块边长的整数倍,所以要注意图像边缘部分的处理。为了能够调整马赛克方块的大小,我们在界面上设置了一个滑块,可以调整滑块来调整马赛克程度:

public BufferedImage drawImage_01(int[][] imgArray){BufferedImage buffimg = new BufferedImage ( imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);System.out.print("iup = "+p);if(p < 20)p = 20;//可使用fillRectfor(int i = p/10; i < imgArray.length; i += (2*(p/10)+1)){for(int j = p/10; j < imgArray[i].length; j += (2*(p/10)+1)){int mm,nn;if(i+(p/10+1)>imgArray.length) {mm = imgArray.length;}else {mm = i+(p/10+1);}if(j+(p/10+1)>imgArray[i].length) {nn = imgArray[i].length;}else {nn = j+(p/10+1);}for(int m=i-p/10;m<mm;m++) {for(int n=j-p/10;n<nn;n++) {buffimg.setRGB (m, n, imgArray[i][j]);}}}}for(int i = imgArray.length-(p/10+1); i < imgArray.length; i++) {int a = imgArray[i].length/(p/10*2+1);for(int m = 0; m < a; m++) {for(int j = (p/10*2+1)*m; j < (p/10*2+1)*(m+1); j++){buffimg.setRGB (i, j, imgArray[imgArray.length-1][(p/10*2+1)*m+(p/10+1)]);}}}int b = imgArray.length/(p/10*2+1);for(int m = 0; m < b; m++) {for(int i = (p/10*2+1)*m; i < (p/10*2+1)*(m+1); i++){for(int j = imgArray[i].length-(p/10+1); j < imgArray[i].length; j++) {buffimg.setRGB (i, j, imgArray[(p/10*2+1)*m+(p/10+1)][imgArray[i].length-1]);}}}for(int i = imgArray.length-(p/10+1); i < imgArray.length; i++){for(int j = imgArray[i].length-(p/10+1); j < imgArray[i].length; j++) {buffimg.setRGB (i, j, imgArray[imgArray.length-1][imgArray[i].length-1]);}}return buffimg;}

滑块值为50: 

滑块值为100:

​         灰度处理直接调佣 getRgbGray 函数即可:

public BufferedImage drawImage_02(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);for(int i = 0; i < imgArray.length; i++){for(int j = 0; j < imgArray[i].length; j++){int num1 = imgArray[i][j];int gray1 = getRgbGray (num1);Color color = new Color (gray1,gray1,gray1);buffimg.setRGB (i, j, color.getRGB ());}}return buffimg;}

​         轮廓处理首先需要识别轮廓,通过比较相邻的像素值,差距过大表示此处颜色差距大(此差距值可以通过人为调整滑块来决定),应该是轮廓边框,然后将此边缘设定为白色,其余部分设定为黑色即可:

public BufferedImage drawImage_03(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);for(int i = 0; i < imgArray.length - 1; i++){for(int j = 1; j < imgArray[i].length - 1; j++){int num1 = imgArray[i][j];int num2 = imgArray[i + 1][j + 1];int num3 = imgArray[i + 1][j - 1];int num4 = imgArray[i + 1][j];int num5 = imgArray[i][j + 1];int gray1 = getRgbGray (num1);int gray2 = getRgbGray (num2);int gray3 = getRgbGray (num3);int gray4 = getRgbGray (num4);int gray5 = getRgbGray (num5);// 比较相邻的像素值 差距过大表示此处颜色差距大 应该是轮廓边框if((Math.abs (gray1 - gray2) > (7+p/10))||(Math.abs (gray1 - gray3) > (7+p/10))||(Math.abs (gray1 - gray4) > (7+p/10))||(Math.abs (gray1 - gray5) > (7+p/10))){// 绘制为白色buffimg.setRGB (i, j, Color.WHITE.getRGB ());} else{// 绘制为黑色buffimg.setRGB (i, j, Color.BLACK.getRGB ());}}}return buffimg;}

二值化处理只需判断该点像素值大小,并设定一个阈值(此阈值大小可以通过人为调整滑块来决定)大于该阈值将该点像素设定为白色,小于该阈值将该点像素设定为黑色:

public BufferedImage drawImage_04(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);for(int i = 0; i < imgArray.length; i++){for(int j = 0; j < imgArray[i].length; j++){int num1 = imgArray[i][j];int gray1 = getRgbGray (num1);if(gray1 > 78+p){// 绘制为白色buffimg.setRGB (i, j, Color.WHITE.getRGB ());} else{// 绘制为黑色buffimg.setRGB (i, j, Color.BLACK.getRGB ());}}}return buffimg;}

​         油画处理即在该图像上画不同大小的椭圆(椭圆的平均大小可以通过人为调整滑块来决定)即可:

public BufferedImage drawImage_05(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);Graphics bg = buffimg.getGraphics();for(int i = (10+p/10); i < imgArray.length; i += (3+p/10)) {for(int j = (5+p/10);j < imgArray[i].length; j += (3+p/10)) {int num = imgArray[i][j];Color color = new Color (num);bg.setColor(color);int r1 = (int)(Math.random()*(40+p/5));int r2 = (int)(Math.random()*(30+p/5));bg.fillOval(i-(20+p/10), j-(15+p/10), Math.max(r1,r2), Math.min(r1,r2));}}return buffimg;}

美白处理(这边我们所做的只是简易的美白,真正美颜相机里的美白需要识别出人物并只美白肤色)只需把图像上每一个像素的 RGB 值增大一定的量(增大量可以通过人为调整滑块来决定)即可:

public BufferedImage drawImage_06(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);for(int i = 0; i < imgArray.length; i++){for(int j = 0; j < imgArray[i].length; j++){int num = imgArray[i][j];Color color = new Color (num);int red = color.getRed ();int green = color.getGreen ();int blue = color.getBlue ();int rednext = red + (3+p/3);if(rednext > 255){rednext = 255;}int greennext = green + (3+p/3);if(greennext > 255){greennext = 255;}int bluenext = blue + (3+p/3);if(bluenext > 255){bluenext = 255;}Color newColor = new Color (rednext, greennext, bluenext);// 缓冲绘制buffimg.setRGB (i, j, newColor.getRGB ());}}return buffimg;}

         至于后面的运动模糊、卷积和锐化处理,其本质都用到了卷积方法,即用不同的卷积核去对图像上的像素值做卷积就可以得到不同的效果。

运动模糊:

public BufferedImage drawImage_07(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);if(p<=50) {int[][] fls= {{1,0,0,0,0},{0,1,0,0,0},{0,0,1,0,0},{0,0,0,1,0},{0,0,0,0,1},};for(int i=0;i<imgArray.length-4;i++) {for(int j=0;j<imgArray[i].length-4;j++) {int redvalue = 0;int greenvalue = 0;int bluevalue = 0;for(int k = 0; k < fls.length; k++) {for (int l = 0; l < fls[k].length; l++) {int rgbvalue = imgArray[i + k][j + l];int red = (rgbvalue >> 16) & 0xFF;int green = (rgbvalue >> 8) & 0xFF;int blue = (rgbvalue) & 0xFF;redvalue += red * fls[k][l];greenvalue += green * fls[k][l];bluevalue += blue * fls[k][l];}}redvalue = redvalue/5;greenvalue = greenvalue/5;bluevalue = bluevalue/5;if(redvalue>255)redvalue=255;if(greenvalue>255)greenvalue=255;if(bluevalue>255)bluevalue=255;if(redvalue<0)redvalue=0;if(greenvalue<0)greenvalue=0;if(bluevalue<0)bluevalue=0;Color newColor = new Color (redvalue, greenvalue, bluevalue);buffimg.setRGB (i, j, newColor.getRGB ());}}}if(p>50) {float[][] fls= {{1,0,0,0,0,0,0,0,0},{0,1,0,0,0,0,0,0,0},{0,0,1,0,0,0,0,0,0},{0,0,0,1,0,0,0,0,0},{0,0,0,0,1,0,0,0,0},{0,0,0,0,0,1,0,0,0},{0,0,0,0,0,0,1,0,0},{0,0,0,0,0,0,0,1,0},{0,0,0,0,0,0,0,0,1},};for(int i=0;i<imgArray.length-8;i++) {for(int j=0;j<imgArray[i].length-8;j++) {int redvalue = 0;int greenvalue = 0;int bluevalue = 0;for(int k=0;k<fls.length;k++) {for (int l = 0; l < fls[k].length; l++) {int rgbvalue = imgArray[i + k][j + l];int red = (rgbvalue >> 16) & 0xFF;int green = (rgbvalue >> 8) & 0xFF;int blue = (rgbvalue) & 0xFF;redvalue += red * fls[k][l];greenvalue += green * fls[k][l];bluevalue += blue * fls[k][l];}}redvalue = redvalue/9;greenvalue = greenvalue/9;bluevalue = bluevalue/9;if(redvalue>255)redvalue=255;if(greenvalue>255)greenvalue=255;if(bluevalue>255)bluevalue=255;if(redvalue<0)redvalue=0;if(greenvalue<0)greenvalue=0;if(bluevalue<0)bluevalue=0;Color newColor = new Color (redvalue, greenvalue, bluevalue);buffimg.setRGB (i, j, newColor.getRGB ());}}}return buffimg;}

         卷积:

public BufferedImage drawImage_08(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);if(p<=50) {int[][] fls= {{-1,-1,0},{-1,0,1},{0,1,1}};for(int i=0;i<imgArray.length-2;i++) {for(int j=0;j<imgArray[i].length-2;j++) {int redvalue = 0;int greenvalue = 0;int bluevalue = 0;for(int k = 0; k < fls.length; k++) {for (int l = 0; l < fls[k].length; l++) {int rgbvalue = imgArray[i + k][j + l];int red = (rgbvalue >> 16) & 0xFF;int green = (rgbvalue >> 8) & 0xFF;int blue = (rgbvalue) & 0xFF;redvalue += red * fls[k][l];greenvalue += green * fls[k][l];bluevalue += blue * fls[k][l];}}if(redvalue>255)redvalue=255;if(greenvalue>255)greenvalue=255;if(bluevalue>255)bluevalue=255;if(redvalue<0)redvalue=0;if(greenvalue<0)greenvalue=0;if(bluevalue<0)bluevalue=0;Color newColor = new Color (redvalue, greenvalue, bluevalue);buffimg.setRGB (i, j, newColor.getRGB ());}}}if(p>50) {float[][] fls= {{-1,-1,-1,-1,0},{-1,-1,-1,0,1},{-1,-1,0,1,1},{-1,0,1,1,1},{0,1,1,1,1},};for(int i=0;i<imgArray.length-4;i++) {for(int j=0;j<imgArray[i].length-4;j++) {int redvalue = 0;int greenvalue = 0;int bluevalue = 0;for(int k=0;k<fls.length;k++) {for (int l = 0; l < fls[k].length; l++) {int rgbvalue = imgArray[i + k][j + l];int red = (rgbvalue >> 16) & 0xFF;int green = (rgbvalue >> 8) & 0xFF;int blue = (rgbvalue) & 0xFF;redvalue += red * fls[k][l];greenvalue += green * fls[k][l];bluevalue += blue * fls[k][l];}}if(redvalue>255)redvalue=255;if(greenvalue>255)greenvalue=255;if(bluevalue>255)bluevalue=255;if(redvalue<0)redvalue=0;if(greenvalue<0)greenvalue=0;if(bluevalue<0)bluevalue=0;Color newColor = new Color (redvalue, greenvalue, bluevalue);buffimg.setRGB (i, j, newColor.getRGB ());}}}return buffimg;}

锐化:

public BufferedImage drawImage_09(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);if(p<=50) {int[][] fls= {{-1,-1,-1},{-1,9,-1},{-1,-1,-1}};for(int i=0;i<imgArray.length-2;i++) {for(int j=0;j<imgArray[i].length-2;j++) {int redvalue = 0;int greenvalue = 0;int bluevalue = 0;for(int k = 0; k < fls.length; k++) {for (int l = 0; l < fls[k].length; l++) {int rgbvalue = imgArray[i + k][j + l];int red = (rgbvalue >> 16) & 0xFF;int green = (rgbvalue >> 8) & 0xFF;int blue = (rgbvalue) & 0xFF;redvalue += red * fls[k][l];greenvalue += green * fls[k][l];bluevalue += blue * fls[k][l];}}if(redvalue>255)redvalue=255;if(greenvalue>255)greenvalue=255;if(bluevalue>255)bluevalue=255;if(redvalue<0)redvalue=0;if(greenvalue<0)greenvalue=0;if(bluevalue<0)bluevalue=0;Color newColor = new Color (redvalue, greenvalue, bluevalue);buffimg.setRGB (i, j, newColor.getRGB ());}}}if(p>50) {float[][] fls= {{-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1},{-1,-1,25,-1,-1},{-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1},};for(int i=0;i<imgArray.length-4;i++) {for(int j=0;j<imgArray[i].length-4;j++) {int redvalue = 0;int greenvalue = 0;int bluevalue = 0;for(int k=0;k<fls.length;k++) {for (int l = 0; l < fls[k].length; l++) {int rgbvalue = imgArray[i + k][j + l];int red = (rgbvalue >> 16) & 0xFF;int green = (rgbvalue >> 8) & 0xFF;int blue = (rgbvalue) & 0xFF;redvalue += red * fls[k][l];greenvalue += green * fls[k][l];bluevalue += blue * fls[k][l];}}if(redvalue>255)redvalue=255;if(greenvalue>255)greenvalue=255;if(bluevalue>255)bluevalue=255;if(redvalue<0)redvalue=0;if(greenvalue<0)greenvalue=0;if(bluevalue<0)bluevalue=0;Color newColor = new Color (redvalue, greenvalue, bluevalue);buffimg.setRGB (i, j, newColor.getRGB ());}}}return buffimg;}

最后一项处理是浮雕效果,浮雕效果的原理是将图像的每一个像素 RGB 值在对角线上作差,并加上 128,最后做灰度处理即可:

public BufferedImage drawImage_10(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);for(int i=0;i<imgArray.length-1;i++) {for(int j=0;j<imgArray[i].length-1;j++) {int redvalue = 0;int greenvalue = 0;int bluevalue = 0;int k=i+1;int l=j+1;int rgbvalue1 = imgArray[i][j];int rgbvalue2 = imgArray[k][l];int red1 = (rgbvalue1>>16)&0xFF;int green1 = (rgbvalue1>>8)&0xFF;int blue1 = (rgbvalue1)&0xFF;int red2 = (rgbvalue2>>16)&0xFF;int green2 = (rgbvalue2>>8)&0xFF;int blue2 = (rgbvalue2)&0xFF;redvalue = red1-red2+128;greenvalue = green1-green2+128;bluevalue = blue1-blue2+128;int gray = (redvalue + greenvalue + bluevalue) / 3;if(gray>255)gray=255;if(gray<0)gray=0;Color newvalue = new Color(gray,gray,gray);buffimg.setRGB (k, l, newvalue.getRGB());}}for(int i=0;i<imgArray.length;i++) {int rgbvalue = imgArray[i][0];int gray = getRgbGray(rgbvalue);Color color = new Color(gray,gray,gray);buffimg.setRGB (i, 0, color.getRGB());}for(int j=0;j<imgArray[0].length;j++) {int rgbvalue = imgArray[0][j];int gray = getRgbGray(rgbvalue);Color color = new Color(gray,gray,gray);buffimg.setRGB (0, j, color.getRGB());}return buffimg;}

旋转处理需要先定义一个空的二维数组,宽度和高度和先前的 imgArray[ ][ ] 的宽度高度相反

左旋使用此代码:newArr[j][imgArray.length-i-1] = imgArray[i][j];

右旋使用此代码:newArr[imgArray.length-j-1][i] = imgArray[i][j];

放大处理只需将画布增大相应尺寸即可(增大量可以通过人为调整滑块来决定);

缩小处理只需将画布增大相应尺寸即可(缩小量可以通过人为调整滑块来决定);

美颜相机最重要的一步来啦,就是打开摄像头和关闭摄像头,此功能需要用到外部 jar 包,下载网站如下:Webcam Capture in Javahttp://webcam-capture.sarxos.pl/

开启摄像头需要用到多线程:

public class ThreadPixel extends Thread {public Graphics g;public boolean flag = true;  //控制线程的标记//初始化画笔对象public ThreadPixel(Graphics g) {this.g = g;}// 启动线程后自定执行的方法// run 方法执行完,该线程结束,线程一旦结束不能再次启动public void run() {System.out.println("启动线程.."+this.getName());// 启动摄像头,放在线程中启动Webcam webcam = Webcam.getDefault();webcam.open();while (flag) {// 获取摄像头拍到的数据BufferedImage bufferedImage = webcam.getImage();g.drawImage(bufferedImage, 50, 50,800,600, null);}}
}

到现在为止,图像处理部分我们就讲完啦,由于画图板功能较图像处理简单,在此我们就不做详细解释,读者直接看文末源代码即可:

这边附上几张画图板效果图:

三、源代码

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;public class DrawUI {ImageListener ul = new ImageListener();ImagePanel imgPanel = new ImagePanel();ImageUtils iu = new ImageUtils();public void initUI(){JFrame jf = new JFrame();jf.setSize(1400,900);jf.setTitle("PC版美颜相机");jf.setLocationRelativeTo(null);jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setVisible(true);JPanel[] jps = addPanel(jf);addButton(jps);addJSlider(jps);addMenu(jf);Graphics gr = imgPanel.getGraphics();ul.g = gr;ul.imgPanel = imgPanel;imgPanel.imglist = ul.imglist;imgPanel.shapeArr = ul.shapeArr;}private void addJSlider(JPanel[] jps) {JLabel j0 = new JLabel("                                                ");j0.setFont(new Font("黑体",1,30));jps[2].add(j0);JLabel j1 = new JLabel("大小/程度选择:");j1.setFont(new Font("黑体",1,30));jps[2].add(j1);JSlider jSlider = new JSlider(0,100);Dimension dm = new Dimension(300,80);  //设置按钮尺寸jSlider.setPreferredSize (dm);jSlider.setFont (new Font ("黑体",1,15));jSlider.setMajorTickSpacing(20);jSlider.setMinorTickSpacing(5);jSlider.setPaintLabels(true);//确定是否在滑块上绘制标签jSlider.setPaintTicks(true);//确定是否在滑块上绘制刻度标记jSlider.setPaintTrack(true);//确定是否在滑块上绘制滑道jSlider.setSnapToTicks(true);//指定为 true,则滑块(及其所表示的值)解析为最靠近用户放置滑块处的刻度标记的值jSlider.setOpaque(false);jps[2].add(jSlider);jSlider.addChangeListener(new ChangeListener() {@Overridepublic void stateChanged(ChangeEvent e) {System.out.println("当前值: " + jSlider.getValue());int p = jSlider.getValue();iu.p = p;}});}private void addMenu(JFrame jf) {//菜单栏JMenuBar jmb = new JMenuBar();jf.add(jmb,BorderLayout.NORTH);//菜单选项JMenu file = new JMenu("文件");file.setPreferredSize(new Dimension(80,40));file.setFont(new Font("宋体",2,22));jmb.add(file);//子菜单JMenuItem jmi1 = new JMenuItem("打开");jmi1.setPreferredSize(new Dimension(80,40));jmi1.setFont(new Font("宋体",2,22));jmi1.addActionListener(ul);file.add(jmi1);JMenuItem jmi2 = new JMenuItem("保存");jmi2.setPreferredSize(new Dimension(80,40));jmi2.setFont(new Font("宋体",2,22));jmi2.addActionListener(ul);file.add(jmi2);jf.setVisible(true);}private void addButton(JPanel[] jps) {String[] btnstrs1 = new String[]{"原图","撤回","马赛克","灰度","轮廓","二值化","油画","美白","运动模糊","卷积","锐化","浮雕","左旋","右旋","放大","缩小","打开摄像头","关闭摄像头"};for(int i = 0; i < btnstrs1.length-2; i++){JButton btn = new JButton(btnstrs1[i]);Dimension dim = new Dimension(120,40);btn.setPreferredSize(dim);btn.setFont(new Font("黑体",1,20));btn.setBackground(Color.WHITE);btn.addActionListener(ul);jps[2].add(btn);}for(int i = btnstrs1.length-2; i < btnstrs1.length; i++){JButton btn = new JButton(btnstrs1[i]);Dimension dim = new Dimension(200,40);btn.setPreferredSize(dim);btn.setFont(new Font("黑体",1,20));btn.setBackground(Color.WHITE);btn.addActionListener(ul);jps[2].add(btn);}String[] btnstrs2 = new String[] {"直线","矩形","椭圆","三角形","正方形","菱形","特殊三角形","多边形","画点","迭代","树"};for(int i = 0; i < btnstrs2.length; i++) {JButton btn = new JButton(btnstrs2[i]);Dimension dim = new Dimension(120,40);btn.setPreferredSize (dim);btn.setFont (new Font ("黑体",1,16));btn.setBackground (Color.WHITE);btn.addActionListener (ul);jps[1].add (btn);}Color []color= {Color.BLUE,Color.GREEN,Color.YELLOW,Color.BLACK,Color.ORANGE,Color.GRAY,Color.RED};for(int i=0;i<color.length;i++) {JButton jbui=new JButton();jbui.setBackground(color[i]);Dimension dmi=new Dimension(40,40);jbui.setPreferredSize(dmi);jbui.addActionListener(ul);jps[1].add(jbui);}}private JPanel[] addPanel(JFrame jf) {JPanel[] jps = new JPanel[3];String[] layoustrs = {BorderLayout.CENTER,BorderLayout.SOUTH,BorderLayout.EAST};imgPanel.setBackground(Color.LIGHT_GRAY);imgPanel.addMouseListener(ul);jf.add(imgPanel,layoustrs[0]);jps[0] = imgPanel;Dimension dim = new Dimension(320,100);JPanel jp_s1 = new JPanel();jp_s1.setBackground(Color.ORANGE);jp_s1.setPreferredSize(dim);jf.add(jp_s1,layoustrs[1]);jps[1] = jp_s1;JPanel jp_s2 = new JPanel();jp_s2.setBackground(Color.YELLOW);jp_s2.setPreferredSize(dim);jf.add(jp_s2,layoustrs[2]);jps[2] = jp_s2;return jps;}public static void main(String[] args) {DrawUI ui = new DrawUI();ui.initUI();}}
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.util.ArrayList;public class ImageListener implements MouseListener, ActionListener {public Graphics g = null;public int p;public ImagePanel imgPanel;public ArrayList <BufferedImage> imglist = new ArrayList<>();private String name = null;public int flag = 1;public int x1,y1,x2,y2,x3,y3,x4,y4;public Color color;public MyShape[] shapeArr = new MyShape[100];public int index;boolean flag1 = false;public ThreadPixel tp;ImageUtils imageUtils = new ImageUtils ();int[][] readImagePixArray = imageUtils.readImagePix ("D:/img1.png");BufferedImage buffimg = null;@Overridepublic void actionPerformed(ActionEvent e) {name = e.getActionCommand();if (name.equals ("原图")) {buffimg = imageUtils.drawImage_00 (readImagePixArray);imglist.add (buffimg);imgPanel.repaint();}else if (name.equals("撤回")) {imglist.remove(imglist.size() - 1);imgPanel.repaint();}else if (name.equals("马赛克")) {buffimg = imageUtils.drawImage_01 (readImagePixArray);imglist.add (buffimg);imgPanel.repaint();}else if (name.equals("灰度")) {buffimg = imageUtils.drawImage_02 (readImagePixArray);imglist.add (buffimg);imgPanel.repaint();}else if (name.equals("轮廓")) {buffimg = imageUtils.drawImage_03 (readImagePixArray);imglist.add (buffimg);imgPanel.repaint();}else if (name.equals("二值化")) {buffimg = imageUtils.drawImage_04 (readImagePixArray);imglist.add (buffimg);imgPanel.repaint();}else if (name.equals("油画")) {buffimg = imageUtils.drawImage_05 (readImagePixArray);imglist.add (buffimg);imgPanel.repaint();}else if (name.equals("美白")) {buffimg = imageUtils.drawImage_06 (readImagePixArray);imglist.add (buffimg);imgPanel.repaint();}else if (name.equals("运动模糊")) {buffimg = imageUtils.drawImage_07 (readImagePixArray);imglist.add (buffimg);imgPanel.repaint();}else if (name.equals("卷积")) {buffimg = imageUtils.drawImage_08 (readImagePixArray);imglist.add (buffimg);imgPanel.repaint();}else if (name.equals("锐化")) {buffimg = imageUtils.drawImage_09 (readImagePixArray);imglist.add (buffimg);imgPanel.repaint();}else if (name.equals("浮雕")) {buffimg = imageUtils.drawImage_10 (readImagePixArray);imglist.add (buffimg);imgPanel.repaint();}else if (name.equals("左旋")) {buffimg = imageUtils.drawImage_11 (readImagePixArray);imglist.add (buffimg);imgPanel.repaint();}else if (name.equals("右旋")) {buffimg = imageUtils.drawImage_12 (readImagePixArray);imglist.add (buffimg);imgPanel.repaint();}else if (name.equals("放大")) {imageUtils.drawImage_13 (readImagePixArray);imgPanel.repaint();}else if (name.equals("缩小")) {imageUtils.drawImage_14 (readImagePixArray);imgPanel.repaint();}else if (name.equals("打开摄像头")) {// 启动多线程// 创建线程对象,显示该线程创建一次if (tp == null) {tp = new ThreadPixel(g);tp.flag = true;// 启动线程tp.start();}}else if (name.equals("关闭摄像头")) {tp.flag = false;}if("".equals(e.getActionCommand())) {JButton jbu=(JButton)e.getSource();color=jbu.getBackground();g.setColor(color);}if("画点".equals(name)) {int xa,xb,xc,xd,ya,yb,yc,yd;xa=(int)(Math.random()*920+50);xb=(int)(Math.random()*920+50);xc=(int)(Math.random()*920+50);xd=(int)(Math.random()*920+50);ya=(int)(Math.random()*800+50);yb=(int)(Math.random()*800+50);yc=(int)(Math.random()*800+50);yd=(int)(Math.random()*800+50);for (int i=0;i<10000;i++) {p=(int)(Math.random()*900);if(p<300&&p>=0) {g.drawLine((xa+xd)/2, (ya+yd)/2, (xa+xd)/2, (ya+yd)/2);xd=(xa+xd)/2;yd=(ya+yd)/2;}else if(p<600&&p>=300) {g.drawLine((xb+xd)/2, (yb+yd)/2, (xb+xd)/2, (yb+yd)/2);xd=(xb+xd)/2;yd=(yb+yd)/2;}else {g.drawLine((xc+xd)/2, (yc+yd)/2, (xc+xd)/2, (yc+yd)/2);xd=(xc+xd)/2;yd=(yc+yd)/2;}}}if("迭代".equals(name)) {double x=0,y=0;double a=-1.7,b=-2.5,c=-2,d=-2;for (int i=0;i<100000;i++) {x=d*Math.sin(a*x)-Math.sin(b*y);y=c*Math.cos(a*x)-Math.cos(b*y);int m=(int)((d*Math.sin(a*x)-Math.sin(b*y))*100+500);int n=(int)((c*Math.cos(a*x)+Math.cos(b*y))*100+350);g.setColor(new Color(250,i%255,i%155));g.drawLine(m, n, m, n);}}if("树".equals(name)) {double x=0,y=0,xn=0,yn=0;for (int i=0;i<100000;i++) {int p1=(int)(Math.random()*1000);if(p1<200&&p1>=0) {double a=0.1950,b=-0.4880,c=0.3440,d=0.4430,ee=0.4431,f=0.2452;xn=a*x+b*y+ee;yn=c*x+d*y+f;System.out.println("x="+xn+"  y="+yn);g.drawLine((int)(900-xn*1000), (int)(900-yn*1000), (int)(900-xn*1000), (int)(900-yn*1000));x=xn;y=yn;}else if(p1<400&&p1>=200) {double a=0.4620,b=0.4140,c=-0.2520,d=0.3610,ee=0.2511,f=0.5692;xn=a*x+b*y+ee;yn=c*x+d*y+f;System.out.println("x="+xn+"  y="+yn);g.drawLine((int)(900-xn*1000), (int)(900-yn*1000), (int)(900-xn*1000), (int)(900-yn*1000));x=xn;y=yn;}else if(p1<600&&p1>=400) {double a=-0.6370,b=0.0000,c=0.0000,d=0.5010,ee=0.8562,f=0.2512;xn=a*x+b*y+ee;yn=c*x+d*y+f;System.out.println("x="+xn+"  y="+yn);g.drawLine((int)(900-xn*1000), (int)(900-yn*1000), (int)(900-xn*1000), (int)(900-yn*1000));x=xn;y=yn;}else if(p1<800&&p1>=600) {double a=-0.0350,b=0.0700,c=-0.4690,d=0.0220,ee=0.4884,f=0.5069;xn=a*x+b*y+ee;yn=c*x+d*y+f;System.out.println("x="+xn+"  y="+yn);g.drawLine((int)(900-xn*1000), (int)(900-yn*1000), (int)(900-xn*1000), (int)(900-yn*1000));x=xn;y=yn;}else {double a=-0.0580,b=-0.0700,c=0.4530,d=-0.1110,ee=0.5976,f=0.0969;xn=a*x+b*y+ee;yn=c*x+d*y+f;System.out.println("x="+xn+"  y="+yn);g.drawLine((int)(900-xn*1000), (int)(900-yn*1000), (int)(900-xn*1000), (int)(900-yn*1000));x=xn;y=yn;}}}}@Overridepublic void mouseClicked(MouseEvent e) {x4=e.getX();y4=e.getY();if("特殊三角形".equals(name)&&flag==2) {g.drawLine(x1, y1, x4, y4);g.drawLine(x2, y2, x4, y4);flag = 1;MyShape shape1 = new MyShape();shape1.name = name;shape1.color = color;shape1.x1 = x1;shape1.x2 = x4;shape1.y1 = y1;shape1.y2 = y4;shapeArr[index++] = shape1;MyShape shape2 = new MyShape();shape2.name = name;shape2.color = color;shape2.x1 = x4;shape2.x2 = x2;shape2.y1 = y4;shape2.y2 = y2;shapeArr[index++] = shape2;}if("多边形".equals(name)&&flag==2) {if(!flag1) {x3=x2;y3=y2;flag1=true;}g.drawLine(x3, y3, x4, y4);MyShape shape3 = new MyShape();shape3.name=name;shape3.color=color;shape3.x1=x4;shape3.x2=x3;shape3.y1=y4;shape3.y2=y3;shapeArr[index++]=shape3;x3=x4;y3=y4;if(e.getClickCount() == 2) {g.drawLine(x1, y1, x4, y4);flag=1;MyShape shape4 = new MyShape();shape4.name=name;shape4.color=color;shape4.x1=x4;shape4.x2=x1;shape4.y1=y4;shape4.y2=y1;shapeArr[index++]=shape4;}}}@Overridepublic void mousePressed(MouseEvent e) {if(flag==1){x1=e.getX();y1=e.getY();}}@Overridepublic void mouseReleased(MouseEvent e) {System.out.println("x1="+x1+";y1="+y1+";x2="+x2+";y2="+y2);if(flag==1){x2=e.getX();y2=e.getY();}if("直线".equals(name)){g.drawLine(x1, y1, x2, y2);}if("矩形".equals(name)){g.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2-x1), Math.abs(y2-y1));}if("椭圆".equals(name)){g.drawOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2-x1), Math.abs(y2-y1));}if("三角形".equals(name)){int[]xPoints=new int[] {x1,(x1+x2)/2,x2};int[]yPoints=new int[] {y2,y1,y2};int nPoints=3;g.drawPolygon(xPoints, yPoints, nPoints);}if("正方形".equals(name)){g.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2-x1), Math.abs(x2-x1));}if("菱形".equals(name)){int[]xPoints=new int[] {(x1+x2)/2,x2,(x1+x2)/2,x1};int[]yPoints=new int[] {y2,(y1+y2)/2,y1,(y1+y2)/2};int nPoints=4;g.drawPolygon(xPoints, yPoints, nPoints);}if("特殊三角形".equals(name)&&flag==1){g.drawLine(x1,y1,x2,y2);flag++;}if("多边形".equals(name)&&flag==1){g.drawLine(x1,y1,x2,y2);flag++;}MyShape shape = new MyShape();shape.name = name;shape.color = color;shape.x1 = x1;shape.x2 = x2;shape.y1 = y1;shape.y2 = y2;shapeArr[index++] = shape;}@Overridepublic void mouseEntered(MouseEvent e) {}@Overridepublic void mouseExited(MouseEvent e) {}
}
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;public class ImagePanel extends JPanel {public ArrayList<BufferedImage> imglist = new ArrayList<>();public MyShape[] shapeArr = new MyShape[100];public static int width;public static int height;public void paint(Graphics gr) {super.paint(gr);System.out.println ("绘制" + getWidth () + " " + getHeight ());if(imglist.size () > 0){BufferedImage buffimg = imglist.get (imglist.size () - 1);BufferedImage newBuffimg = new BufferedImage (width,height,BufferedImage.TYPE_INT_ARGB);Graphics bg = newBuffimg.getGraphics ();bg.drawImage (buffimg,0,0,width,height,null);gr.drawImage (newBuffimg,0,0,null);}System.out.println("绘制组件!");for(int i = 0; i < shapeArr.length; i++) {if (shapeArr[i] == null) break;MyShape shape = shapeArr[i];shape.drawShape(gr);}}
}
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;// 继承JPanel 重写paint 方法
public class ImageUtils{public static int p = 50;ImagePanel imgPanel = new ImagePanel();public int[][] readImagePix(String path){// 文件对象File file = new File (path);BufferedImage readimg = null;try {readimg = ImageIO.read (file);} catch (IOException e) {e.printStackTrace ();}int width = readimg.getWidth ();int height = readimg.getHeight ();int height0 = 0;int width0 = 0;if(width >= height){height0 = width;width0 = width;}if(width < height){width0 = height;height0 = height;}imgPanel.width = width;imgPanel.height= height;int[][] imgArray = new int[width0][height0];for(int i = 0; i < width; i++){for(int j = 0; j < height; j++){imgArray[i][j] = readimg.getRGB (i, j);}}return imgArray;}public int getRgbGray(int numPixels){// byte -128 127int red = (numPixels>>16)&0xFF;int green = (numPixels>>8)&255;int blue = (numPixels>>0)&255;// 灰度 -- 减少计算量 以及 更方便计算int gray = (red + green + blue) / 3;return gray;}//根据二维数组 绘制图片public BufferedImage drawImage_00(int[][] imgArray){BufferedImage buffimg = new BufferedImage ( imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);for(int i = 0; i < imgArray.length; i++){for(int j = 0; j < imgArray[i].length; j++){buffimg.setRGB (i,j,imgArray[i][j]);}}return buffimg;}//根据二维数组 绘制图片public BufferedImage drawImage_01(int[][] imgArray){BufferedImage buffimg = new BufferedImage ( imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);System.out.print("iup = "+p);if(p < 20)p = 20;//可使用fillRectfor(int i = p/10; i < imgArray.length; i += (2*(p/10)+1)){for(int j = p/10; j < imgArray[i].length; j += (2*(p/10)+1)){int mm,nn;if(i+(p/10+1)>imgArray.length) {mm = imgArray.length;}else {mm = i+(p/10+1);}if(j+(p/10+1)>imgArray[i].length) {nn = imgArray[i].length;}else {nn = j+(p/10+1);}for(int m=i-p/10;m<mm;m++) {for(int n=j-p/10;n<nn;n++) {buffimg.setRGB (m, n, imgArray[i][j]);}}}}for(int i = imgArray.length-(p/10+1); i < imgArray.length; i++) {int a = imgArray[i].length/(p/10*2+1);for(int m = 0; m < a; m++) {for(int j = (p/10*2+1)*m; j < (p/10*2+1)*(m+1); j++){buffimg.setRGB (i, j, imgArray[imgArray.length-1][(p/10*2+1)*m+(p/10+1)]);}}}int b = imgArray.length/(p/10*2+1);for(int m = 0; m < b; m++) {for(int i = (p/10*2+1)*m; i < (p/10*2+1)*(m+1); i++){for(int j = imgArray[i].length-(p/10+1); j < imgArray[i].length; j++) {buffimg.setRGB (i, j, imgArray[(p/10*2+1)*m+(p/10+1)][imgArray[i].length-1]);}}}for(int i = imgArray.length-(p/10+1); i < imgArray.length; i++){for(int j = imgArray[i].length-(p/10+1); j < imgArray[i].length; j++) {buffimg.setRGB (i, j, imgArray[imgArray.length-1][imgArray[i].length-1]);}}return buffimg;}//根据二维数组 绘制图片public BufferedImage drawImage_02(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);for(int i = 0; i < imgArray.length; i++){for(int j = 0; j < imgArray[i].length; j++){int num1 = imgArray[i][j];int gray1 = getRgbGray (num1);Color color = new Color (gray1,gray1,gray1);buffimg.setRGB (i, j, color.getRGB ());}}return buffimg;}// 根据二维数组 绘制图片public BufferedImage drawImage_03(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);for(int i = 0; i < imgArray.length - 1; i++){for(int j = 1; j < imgArray[i].length - 1; j++){int num1 = imgArray[i][j];int num2 = imgArray[i + 1][j + 1];int num3 = imgArray[i + 1][j - 1];int num4 = imgArray[i + 1][j];int num5 = imgArray[i][j + 1];int gray1 = getRgbGray (num1);int gray2 = getRgbGray (num2);int gray3 = getRgbGray (num3);int gray4 = getRgbGray (num4);int gray5 = getRgbGray (num5);// 比较相邻的像素值 差距过大表示此处颜色差距大 应该是轮廓边框if((Math.abs (gray1 - gray2) > (7+p/10))||(Math.abs (gray1 - gray3) > (7+p/10))||(Math.abs (gray1 - gray4) > (7+p/10))||(Math.abs (gray1 - gray5) > (7+p/10))){// 绘制为白色buffimg.setRGB (i, j, Color.WHITE.getRGB ());} else{// 绘制为黑色buffimg.setRGB (i, j, Color.BLACK.getRGB ());}}}return buffimg;}// 根据二维数组 绘制图片public BufferedImage drawImage_04(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);for(int i = 0; i < imgArray.length; i++){for(int j = 0; j < imgArray[i].length; j++){int num1 = imgArray[i][j];int gray1 = getRgbGray (num1);if(gray1 > 78+p){// 绘制为白色buffimg.setRGB (i, j, Color.WHITE.getRGB ());} else{// 绘制为黑色buffimg.setRGB (i, j, Color.BLACK.getRGB ());}}}return buffimg;}//根据二维数组 绘制图片public BufferedImage drawImage_05(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);Graphics bg = buffimg.getGraphics();for(int i = (10+p/10); i < imgArray.length; i += (3+p/10)) {for(int j = (5+p/10);j < imgArray[i].length; j += (3+p/10)) {int num = imgArray[i][j];Color color = new Color (num);bg.setColor(color);int r1 = (int)(Math.random()*(40+p/5));int r2 = (int)(Math.random()*(30+p/5));bg.fillOval(i-(20+p/10), j-(15+p/10), Math.max(r1,r2), Math.min(r1,r2));}}return buffimg;}//根据二维数组 绘制图片public BufferedImage drawImage_06(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);for(int i = 0; i < imgArray.length; i++){for(int j = 0; j < imgArray[i].length; j++){int num = imgArray[i][j];Color color = new Color (num);int red = color.getRed ();int green = color.getGreen ();int blue = color.getBlue ();int rednext = red + (3+p/3);if(rednext > 255){rednext = 255;}int greennext = green + (3+p/3);if(greennext > 255){greennext = 255;}int bluenext = blue + (3+p/3);if(bluenext > 255){bluenext = 255;}Color newColor = new Color (rednext, greennext, bluenext);// 缓冲绘制buffimg.setRGB (i, j, newColor.getRGB ());}}return buffimg;}//根据二维数组 绘制图片public BufferedImage drawImage_07(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);if(p<=50) {int[][] fls= {{1,0,0,0,0},{0,1,0,0,0},{0,0,1,0,0},{0,0,0,1,0},{0,0,0,0,1},};for(int i=0;i<imgArray.length-4;i++) {for(int j=0;j<imgArray[i].length-4;j++) {int redvalue = 0;int greenvalue = 0;int bluevalue = 0;for(int k = 0; k < fls.length; k++) {for (int l = 0; l < fls[k].length; l++) {int rgbvalue = imgArray[i + k][j + l];int red = (rgbvalue >> 16) & 0xFF;int green = (rgbvalue >> 8) & 0xFF;int blue = (rgbvalue) & 0xFF;redvalue += red * fls[k][l];greenvalue += green * fls[k][l];bluevalue += blue * fls[k][l];}}redvalue = redvalue/5;greenvalue = greenvalue/5;bluevalue = bluevalue/5;if(redvalue>255)redvalue=255;if(greenvalue>255)greenvalue=255;if(bluevalue>255)bluevalue=255;if(redvalue<0)redvalue=0;if(greenvalue<0)greenvalue=0;if(bluevalue<0)bluevalue=0;Color newColor = new Color (redvalue, greenvalue, bluevalue);buffimg.setRGB (i, j, newColor.getRGB ());}}}if(p>50) {float[][] fls= {{1,0,0,0,0,0,0,0,0},{0,1,0,0,0,0,0,0,0},{0,0,1,0,0,0,0,0,0},{0,0,0,1,0,0,0,0,0},{0,0,0,0,1,0,0,0,0},{0,0,0,0,0,1,0,0,0},{0,0,0,0,0,0,1,0,0},{0,0,0,0,0,0,0,1,0},{0,0,0,0,0,0,0,0,1},};for(int i=0;i<imgArray.length-8;i++) {for(int j=0;j<imgArray[i].length-8;j++) {int redvalue = 0;int greenvalue = 0;int bluevalue = 0;for(int k=0;k<fls.length;k++) {for (int l = 0; l < fls[k].length; l++) {int rgbvalue = imgArray[i + k][j + l];int red = (rgbvalue >> 16) & 0xFF;int green = (rgbvalue >> 8) & 0xFF;int blue = (rgbvalue) & 0xFF;redvalue += red * fls[k][l];greenvalue += green * fls[k][l];bluevalue += blue * fls[k][l];}}redvalue = redvalue/9;greenvalue = greenvalue/9;bluevalue = bluevalue/9;if(redvalue>255)redvalue=255;if(greenvalue>255)greenvalue=255;if(bluevalue>255)bluevalue=255;if(redvalue<0)redvalue=0;if(greenvalue<0)greenvalue=0;if(bluevalue<0)bluevalue=0;Color newColor = new Color (redvalue, greenvalue, bluevalue);buffimg.setRGB (i, j, newColor.getRGB ());}}}return buffimg;}//根据二维数组 绘制图片public BufferedImage drawImage_08(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);if(p<=50) {int[][] fls= {{-1,-1,0},{-1,0,1},{0,1,1}};for(int i=0;i<imgArray.length-2;i++) {for(int j=0;j<imgArray[i].length-2;j++) {int redvalue = 0;int greenvalue = 0;int bluevalue = 0;for(int k = 0; k < fls.length; k++) {for (int l = 0; l < fls[k].length; l++) {int rgbvalue = imgArray[i + k][j + l];int red = (rgbvalue >> 16) & 0xFF;int green = (rgbvalue >> 8) & 0xFF;int blue = (rgbvalue) & 0xFF;redvalue += red * fls[k][l];greenvalue += green * fls[k][l];bluevalue += blue * fls[k][l];}}if(redvalue>255)redvalue=255;if(greenvalue>255)greenvalue=255;if(bluevalue>255)bluevalue=255;if(redvalue<0)redvalue=0;if(greenvalue<0)greenvalue=0;if(bluevalue<0)bluevalue=0;Color newColor = new Color (redvalue, greenvalue, bluevalue);buffimg.setRGB (i, j, newColor.getRGB ());}}}if(p>50) {float[][] fls= {{-1,-1,-1,-1,0},{-1,-1,-1,0,1},{-1,-1,0,1,1},{-1,0,1,1,1},{0,1,1,1,1},};for(int i=0;i<imgArray.length-4;i++) {for(int j=0;j<imgArray[i].length-4;j++) {int redvalue = 0;int greenvalue = 0;int bluevalue = 0;for(int k=0;k<fls.length;k++) {for (int l = 0; l < fls[k].length; l++) {int rgbvalue = imgArray[i + k][j + l];int red = (rgbvalue >> 16) & 0xFF;int green = (rgbvalue >> 8) & 0xFF;int blue = (rgbvalue) & 0xFF;redvalue += red * fls[k][l];greenvalue += green * fls[k][l];bluevalue += blue * fls[k][l];}}if(redvalue>255)redvalue=255;if(greenvalue>255)greenvalue=255;if(bluevalue>255)bluevalue=255;if(redvalue<0)redvalue=0;if(greenvalue<0)greenvalue=0;if(bluevalue<0)bluevalue=0;Color newColor = new Color (redvalue, greenvalue, bluevalue);buffimg.setRGB (i, j, newColor.getRGB ());}}}return buffimg;}//根据二维数组 绘制图片public BufferedImage drawImage_09(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);if(p<=50) {int[][] fls= {{-1,-1,-1},{-1,9,-1},{-1,-1,-1}};for(int i=0;i<imgArray.length-2;i++) {for(int j=0;j<imgArray[i].length-2;j++) {int redvalue = 0;int greenvalue = 0;int bluevalue = 0;for(int k = 0; k < fls.length; k++) {for (int l = 0; l < fls[k].length; l++) {int rgbvalue = imgArray[i + k][j + l];int red = (rgbvalue >> 16) & 0xFF;int green = (rgbvalue >> 8) & 0xFF;int blue = (rgbvalue) & 0xFF;redvalue += red * fls[k][l];greenvalue += green * fls[k][l];bluevalue += blue * fls[k][l];}}if(redvalue>255)redvalue=255;if(greenvalue>255)greenvalue=255;if(bluevalue>255)bluevalue=255;if(redvalue<0)redvalue=0;if(greenvalue<0)greenvalue=0;if(bluevalue<0)bluevalue=0;Color newColor = new Color (redvalue, greenvalue, bluevalue);buffimg.setRGB (i, j, newColor.getRGB ());}}}if(p>50) {float[][] fls= {{-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1},{-1,-1,25,-1,-1},{-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1},};for(int i=0;i<imgArray.length-4;i++) {for(int j=0;j<imgArray[i].length-4;j++) {int redvalue = 0;int greenvalue = 0;int bluevalue = 0;for(int k=0;k<fls.length;k++) {for (int l = 0; l < fls[k].length; l++) {int rgbvalue = imgArray[i + k][j + l];int red = (rgbvalue >> 16) & 0xFF;int green = (rgbvalue >> 8) & 0xFF;int blue = (rgbvalue) & 0xFF;redvalue += red * fls[k][l];greenvalue += green * fls[k][l];bluevalue += blue * fls[k][l];}}if(redvalue>255)redvalue=255;if(greenvalue>255)greenvalue=255;if(bluevalue>255)bluevalue=255;if(redvalue<0)redvalue=0;if(greenvalue<0)greenvalue=0;if(bluevalue<0)bluevalue=0;Color newColor = new Color (redvalue, greenvalue, bluevalue);buffimg.setRGB (i, j, newColor.getRGB ());}}}return buffimg;}//根据二维数组 绘制图片public BufferedImage drawImage_10(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);for(int i=0;i<imgArray.length-1;i++) {for(int j=0;j<imgArray[i].length-1;j++) {int redvalue = 0;int greenvalue = 0;int bluevalue = 0;int k=i+1;int l=j+1;int rgbvalue1 = imgArray[i][j];int rgbvalue2 = imgArray[k][l];int red1 = (rgbvalue1>>16)&0xFF;int green1 = (rgbvalue1>>8)&0xFF;int blue1 = (rgbvalue1)&0xFF;int red2 = (rgbvalue2>>16)&0xFF;int green2 = (rgbvalue2>>8)&0xFF;int blue2 = (rgbvalue2)&0xFF;redvalue = red1-red2+128;greenvalue = green1-green2+128;bluevalue = blue1-blue2+128;int gray = (redvalue + greenvalue + bluevalue) / 3;if(gray>255)gray=255;if(gray<0)gray=0;Color newvalue = new Color(gray,gray,gray);buffimg.setRGB (k, l, newvalue.getRGB());}}for(int i=0;i<imgArray.length;i++) {int rgbvalue = imgArray[i][0];int gray = getRgbGray(rgbvalue);Color color = new Color(gray,gray,gray);buffimg.setRGB (i, 0, color.getRGB());}for(int j=0;j<imgArray[0].length;j++) {int rgbvalue = imgArray[0][j];int gray = getRgbGray(rgbvalue);Color color = new Color(gray,gray,gray);buffimg.setRGB (0, j, color.getRGB());}return buffimg;}//根据二维数组 绘制图片public BufferedImage drawImage_11(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);int[][] newArr = new int[imgArray[0].length][imgArray.length];for(int i = 0; i < imgArray.length; i++) {for (int j = 0; j < imgArray[i].length; j++) {newArr[j][imgArray.length-i-1] = imgArray[i][j];}}for(int i = 0; i < newArr.length; i++) {for (int j = 0; j < newArr[i].length; j++) {imgArray[i][j] = newArr[i][j];buffimg.setRGB(i, j, newArr[i][j]);}}return buffimg;}//根据二维数组 绘制图片public BufferedImage drawImage_12(int[][] imgArray){BufferedImage buffimg = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);int[][] newArr = new int[imgArray[0].length][imgArray.length];for(int i = 0; i < imgArray.length; i++) {for (int j = 0; j < imgArray[i].length; j++) {newArr[imgArray.length-j-1][i] = imgArray[i][j];}}for(int i = 0; i < newArr.length; i++) {for (int j = 0; j < newArr[i].length; j++) {imgArray[i][j] = newArr[i][j];buffimg.setRGB(i, j, newArr[i][j]);}}return buffimg;}//根据二维数组 绘制图片public void drawImage_13(int[][] imgArray){imgPanel.width += p/5;imgPanel.height += p/5;}//根据二维数组 绘制图片public void drawImage_14(int[][] imgArray){imgPanel.width -= p/5;imgPanel.height -= p/5;}}
import java.awt.*;public class MyShape {public int x1,x2,y1,y2;public String name="";public Color color;public void drawShape(Graphics g) {System.out.println("name = "+name);switch(name) {case"直线":g.setColor(color);g.drawLine(x1,y1,x2,y2);break;case"矩形":g.setColor(color);g.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2-x1), Math.abs(y2-y1));break;case"椭圆":g.setColor(color);g.drawOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2-x1), Math.abs(y2-y1));break;case"三角形":g.setColor(color);int[]xPoints1=new int[] {x1,(x1+x2)/2,x2};int[]yPoints1=new int[] {y2,y1,y2};int nPoints1=3;g.drawPolygon(xPoints1,yPoints1,nPoints1);break;case"正方形":g.setColor(color);g.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2-x1), Math.abs(x2-x1));break;case"菱形":g.setColor(color);int[]xPoints2=new int[] {(x1+x2)/2,x2,(x1+x2)/2,x1};int[]yPoints2=new int[] {y2,(y1+y2)/2,y1,(y1+y2)/2};int nPoints2=4;g.drawPolygon(xPoints2, yPoints2, nPoints2);break;case"特殊三角形":g.setColor(color);g.drawLine(x1,y1,x2,y2);break;case"多边形":g.setColor(color);g.drawLine(x1,y1,x2,y2);break;}}
}
import java.awt.Graphics;
import java.awt.image.BufferedImage;import com.github.sarxos.webcam.Webcam;//定义线程类
public class ThreadPixel extends Thread {public Graphics g;public boolean flag = true;  //控制线程的标记//初始化画笔对象public ThreadPixel(Graphics g) {this.g = g;}// 启动线程后自定执行的方法// run 方法执行完,该线程结束,线程一旦结束不能再次启动public void run() {System.out.println("启动线程.."+this.getName());// 启动摄像头,放在线程中启动Webcam webcam = Webcam.getDefault();webcam.open();while (flag) {// 获取摄像头拍到的数据BufferedImage bufferedImage = webcam.getImage();g.drawImage(bufferedImage, 50, 50,800,600, null);}}
}

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

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

    一.思路分析 一款简易美颜相机的功能我们可以简单分为两大块:1.图像处理    2.功能区 最终的效果图如下: 二.代码分析 图像处理工具的本质是处理像素点,而像素点的本质就是一种颜色,每一个像素点都 ...

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

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

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

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

  4. java简易画图程序代码_java_简易画图板

    下面我将分享用Java制作简易画图板的过程. version 1 Draw.java Java代码 importjavax.swing.JFrame; /** * * @author yangzhen ...

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

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

  6. 基于MATLAB的仿windows画图板功能的实现

    1.仿真预览 2.部分核心代码 % --- Executes on selection change in popupmenu2. function popupmenu2_Callback(hObje ...

  7. java,制作简易画图板

    简易画图板 前些日子,我学习了关于xp系统简易画图板的制作,虽然我写的画图板功能不多,但这是我接触java以来完成的第一个项目,制作的时候感觉很艰难,有的时候明明知道思路,却因为不知道具体的方法而走了 ...

  8. qt制作一个画板_基于Qt的画图板的设计与实现(含录像)

    基于Qt的画图板的设计与实现(含录像)(任务书,开题报告,外文翻译,毕业论文20000字,程序代码,答辩PPT,答辩视频录像) 摘要 本文的主要内容是记述画图板的设计与实现课程设计中的一些关键技术和辅 ...

  9. 计算机模块中的画板英文,画图板

    数位画图板:简称数位板.画图板.绘图板.绘画板.手绘板等等,是计算机输入设备的一种,数位画图板同键盘.鼠标.手写板一样都是计算机输入设备.数位画图板是专门针对电脑插画设计为研发的产品,数位画图板作为一 ...

最新文章

  1. suse mysql 5.5_suse 11 mysql 如何从5.1升级到5.5
  2. C语言中常用的数学公式
  3. Rabbit寻宝记(1)
  4. Ubuntu安装amule和编译安装amule-dlp
  5. linux mysql 停止,linux 里 重启 和停止 mysql的原理
  6. android-api28转换到api19-不能编译
  7. 计算机网络阶段,计算机网络的发展大致可分为四个阶段,目前人类进入了()。 - 问答库...
  8. rageframe2 数据库配置_RF 微商城 一款基于 RageFrame2 的免费开源的基础销售功能的微商城...
  9. python 数据库查询结果邮件提醒_python读取postgresql数据库并发送相关提醒邮件
  10. STM32-通用定时器-输入捕获
  11. Java中需要全部小写的是,java – 如何处理JSR 310中的大写或小写?
  12. 循序渐进!java开发手册阿里巴巴泰山版
  13. 教你如何使用ip地址进行高精度定位
  14. 你该知道的杂志分区和影响因子及最新表格下载
  15. 爱的台阶之危险流浪者
  16. unbuntu网卡配置
  17. 解决电脑能连接WIFI但是无法正常上网问题
  18. Kubernetes 污点和容忍
  19. 期货CTP接口C++源码与C#应用程序的对接
  20. r语言ggplot2一夜多图_关于GGPLOT2出图里的一页多图模式

热门文章

  1. Java绘制海螺_3DMAX制作海螺工艺品教程 - 纳金网
  2. 一种基于神经网络的由PPG信号估计连续血压算法【翻译】
  3. 刺激战场c语言,刺激战场各种代码,搬运3楼。
  4. C语言 计算sinx的近似值
  5. matplotlib画3D图形时设置z轴尺寸
  6. Android版Siri——Jeannie 评测
  7. 计算机专业大学老师好吗,天津师范大学计算机专业那个老师比较好
  8. Linux系统之ping命令
  9. 加载预训练模型时报错 KeyError: param ‘initial_lr‘ is not specified in param_groups[0]
  10. 升级镁光M4固态硬盘的固件