美颜相机的实现(利用Webcam)
如何实现美颜相机?
首先,需要导入三个外部jar包来调用摄像头
美颜相机是要调用我们的电脑摄像头实时获取我们的视频数据,视频就是由一帧一帧的图片组成的,所以我们需要先将一张图片如何处理了解明白。
第一步
我们需要打开摄像头,然后创建一个Webcam对象,为此我专门写了一个open方法来打开摄像头
public void open(){Webcam webcam=Webcam.getDefault();webcam.setViewSize(new Dimension(640, 480));wb=webcam;webcam.open();}
第二步
我们采用图片缓冲区BufferedImage来存取摄像头传来的某一帧图片
BufferedImage buffimage =wb.getImage();
为什么采用图片缓冲区来存储图像呢?这里你可以将它看作一个自由的画布,先往这个自由的画布上画上你想画的东西,然后再将这个自由的画布当作一幅画,整个画到窗体上。
当你经常改变要画的东西时,只在图片缓冲区中该变即可,将所有的该变完成后再显视到窗体上,这样窗体上的动画就不会因为一步一步刷新而闪烁了。
第三步(重难点)
就是美颜相机最关键也是最难的一步,如何从图片缓冲区得到图片像素值?
一张图片有长宽,所以用一个二维数组来保存图片所有的像素值。一个RGB占三个字节,一个int型是占四个字节,所以用一个int型二维数组来保存图片像素值。
public int[][] getImagePixel(BufferedImage image){}
由第二步我们得到了一个图片缓冲区,所以调用该方法就可以,那么重点来了,方法体怎么写?
int[][] im=new int[image.getWidth()][image.getHeight()];//新建二维数组,宽高由getWidth()和getHeight()确定
然后遍历二维数组,将缓冲区的每一个像素值传给二维数组相应位置。
for(int i=0;i<image.getWidth();i++) {for(int j=0;j<image.getHeight();j++) {im[i][j]=image.getRGB(i, j);} }
很多同学认为我们这就已经完成了,但是并不是这样,这得到的图像是左右颠倒的,白话就是举起右手,图像里左手举起来了,所以我们要将左右交换一下。
for(int i=0;i<im[0].length;i++) {for(int j=0;j<im.length/2;j++) {int temp=im[j][i];im[j][i]=im[im.length-j-1][i];im[im.length-j-1][i]=temp;}}
这时候才是完成对图像缓冲区中像素点的全部存取,返回一个二维数组,用来进行下一步的图像处理。
第四步
为我们的图片添加特效
我们拿图片底片效果来举个例子,首先传入二维数组。
public BufferedImage dipian(int[][] im) {BufferedImage bf=null;bf=new BufferedImage(jm.getWidth(),jm.getHeight(),BufferedImage.TYPE_3BYTE_BGR);//**让图片缓冲区的高宽适应我们的Frame框架**for(int i=0;i<im.length;i++) {for(int j=0;j<im[i].length;j++) {Color rgb=new Color(im[i][j]);//**将二维数组存储的像素点转化为Color对象**int a=255-rgb.getRed();//**调用Color对象的getRed()方法**int b=255-rgb.getGreen();int c=255-rgb.getBlue();Color cc=new Color(a,b,c);//**将处理好的红绿蓝三原色赋给新的Color对象**bf.setRGB(i, j, cc.getRGB());//**将Color对象用getRGB()方法将新的RGB赋给图片缓冲区相对应的点**} }//**拍照(截图)功能,通过ImageIO的write方法写入自己命名的文件**if(btn.equals("拍照")){try {ImageIO.write(bf, "JPG", f);//**f为事先创建好的文件对象,将截图以JPG格式写入文件对象**} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}return bf;//**返回处理好的图片缓冲区**}
第五步
输出效果
gr.drawImage(dipian(image), 0, 0, null);//gr为画笔对象,使用drawImage方法将上一步处理好的图片缓冲区画在画布上
效果图
其他的图片处理代码举例:
//**灰度**public BufferedImage grey(int[][] im) {BufferedImage bf=new BufferedImage(jm.getWidth(),jm.getHeight(),BufferedImage.TYPE_3BYTE_BGR);;for(int i=0;i<im.length;i++) {for(int j=0;j<im[i].length;j++) {Color c=new Color(im[i][j]);int r=c.getRed();int g=c.getGreen();int b=c.getBlue();int sum=(int)(r*0.3+g*0.3+b*0.4);Color nc=new Color(sum,sum,sum);bf.setRGB(i, j, nc.getRGB());}}if(btn.equals("拍照")){try {ImageIO.write(bf, "JPG", b);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}return bf;}//**马赛克**
public void masaike(Graphics g,int[][] im) {BufferedImage bf=null;bf=new BufferedImage(jm.getWidth(),jm.getHeight(),BufferedImage.TYPE_3BYTE_BGR);Graphics m=bf.getGraphics();for(int i=0;i<im.length;i+=10) {for(int j=0;j<im[i].length;j+=10) {Color c=new Color(im[i][j]);m.setColor(c);m.fillRect(i, j, 10,10);}}if(btn.equals("拍照")){try {ImageIO.write(bf, "JPG", c);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}g.drawImage(bf, 0, 0, null);}
总结与收获
经过近两个星期的学习,让我对于如何处理图片和视频有了全新的认识,学到了图像处理中很多独特的方,知道了Color类和图片缓冲区的用法,其中还涉及到了一些多线程的基础知识,在线程的run()方法中调用了图像处理的各种方法,这样我们得到的就是视频而不是一张张静态图片。感谢老师和小组其他成员的帮助,让我的基础能力也有了巩固和提高,这个项目对我个人意义重大。