Java快速上手图像处理(包含图像卷积及支持开摄像头)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_44807642/article/details/98205162

这段时间我对Java进行图像处理,进行了学习。所谓图像处理,就是用Java先对图片的每个像素点进行循环遍历。然后对像素点进行操作,实现对整张图片进行图像处理的目的。

博主已经把自己的代码上传到自己的资源,大家需要自取。

一.解析原图

解析原图就是上面提到的对每个像素点进行遍历,然后用一个二维数组对像素点的RGB值进行进行保存,达到对RGB值更改的目的,整张图片就也会被更改。RGB值的百度百科定义如下;在这里插入图片描述
解析原图的代码如下:

public void load() {
		File file = new Filedemo().openFile();
		if(file==null) {
			return;
		}
		try {
			//加载图片
			BufferedImage buffer = ImageIO.read(file);
		    data = new int[buffer.getHeight()][buffer.getWidth()];
		    newdata = new int[buffer.getHeight()+2][buffer.getWidth()+2];
			//获取图片数据
		    draw.buffer=buffer;
			for(int i=0;i<buffer.getHeight();i++) {
				for(int j=0;j<buffer.getWidth();j++) {
					data[i][j]=buffer.getRGB(j, i);
				}
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

其中的
File file = new Filedemo().openFile()
这一行是我设置了一个文件打开器,file是我打开的图片文件,我用data来对图片信息储存,newdata是用来下面的卷积特效做准备。在其他的特效,如马赛克,老时光,底片,黑白等效果中不需要用到。

原图效果

在上面的加载过程完成后,我们选择的图像信息就存在了data数组里面,然后对数组再次进行遍历画点,便可以将原图绘出。
代码如下:

  //原图
	public void yuantu(Graphics g) {		
	
		for(int i=0;i<data.length;i++) {
			for(int j=0;j<data[i].length;j++) {
				int value=data[i][j];
				Color color = new Color(data[i][j]);
				bg.setColor(color);
				bg.drawLine(j+120, i+80, j+120, i+80);
			
			}			
		}
		//绘制缓存到窗体上
		g.drawImage(buffer, 0, 0, null);
	}

其中buffer是我存在缓存的图片,如果不把图片存在缓存的话,图片就会一行一行的慢速加载,而先存在缓存里面再在画布g中显示出来的话,就会快速的显示出来。
如下图,是我用我的连连看开始画面的原图。
在这里插入图片描述

黑白效果

		//黑白
	public void BlackWhite(Graphics g) {
 for(int i=0;i<data.length;i++) {
			for(int j=0;j<data[i].length;j++) {
				int value=data[i][j];
				int red = (0x00ff0000&value)>>16;
				int green = (0x0000ff00&value)>>8;
				int blue = 0xff&value; 
				c =new Color(blue,blue,blue); 
				
				bg.setColor(c);
				bg.drawLine(j+120, i+80, j+120, i+80);
				//先画到缓存bg里面,然后再画的时候就直接出来了
			}
		}//绘制缓存到窗体上
				g.drawImage(buffer, 0, 0, null);
	}

黑白效果很简单,就是每个点的RGB值设为相同的。就会单点显示黑or白,然后整体就是黑白效果了。放一张效果图。
在这里插入图片描述

马赛克特效

马赛克特效就是把点变为一个个小矩形去填充,代码也比较容易,所以直接贴代码了。
代码中的画点就由画点变为填充矩形了。
bg.fillRect(j+120,i+80,20,20);

	//马赛克
	public void Mosaic(Graphics g) {
	for(int i=0;i<data.length;i+=20) {
			for(int j=0;j<data[i].length;j+=20) {
				int value=data[i][j];
				int red = (0x00ff0000&value)>>16;
				int green = (0x0000ff00&value)>>8;
				int blue = 0xff&value; 
				c =new Color(red,green,blue);  
				bg.setColor(c);
				bg.fillRect(j+120,i+80,20,20);
				
			}
		}
		//绘制缓存到窗体上
		g.drawImage(buffer, 0, 0, null);

	}

贴一张效果图
在这里插入图片描述

底片特效

底片的效果就是拿原图的rgb值被255减去就好了。代码也很简单,就直接贴代码与效果图了。

  //底片
    public void dipian(Graphics g) {
		
		for(int i=0;i<data.length;i++) {
			for(int j=0;j<data[i].length;j++) {
				int value=data[i][j];
				int red = 255-((0x00ff0000&value)>>16);
				int green = 255-((0x0000ff00&value)>>8);
				int blue = 255-(0xff&value); 
				c=new Color(red,green,blue);
				bg.setColor(c);
				bg.drawLine(j+120, i+80, j+120, i+80);
			}			
		}
		//绘制缓存到窗体上
		g.drawImage(buffer, 0, 0, null);
	}

效果图如下:
在这里插入图片描述

旧时光特效

旧时光特效就是在原图的基础上,让相片看上去有点怀旧的感觉。

	//老时光
	public void old(Graphics g) {
	
		for(int i=0;i<data.length;i++) {
			for(int j=0;j<data[i].length;j++) {
				int value=data[i][j];
				int red = (0x00ff0000&value)>>16;
				int green = (0x0000ff00&value)>>8;
				int blue = 0xff&value; 
				
				 int fr = (int)colorBlend(noise(), (red * 0.393) + (green * 0.769) + (blue * 0.189), red);  
	                int fg = (int)colorBlend(noise(), (red * 0.349) + (green * 0.686) + (blue * 0.168), green);  
	                int fb = (int)colorBlend(noise(), (red * 0.272) + (green * 0.534) + (blue * 0.131), blue);
	
				
				c =new Color(clamp(fr),clamp(fg),clamp(fb));  
				bg.setColor(c);
				bg.drawLine(j+120, i+80, j+120, i+80);
				//先画到缓存bg里面,然后再画的时候就直接出来了
			}
		}
		//绘制缓存到窗体上
				g.drawImage(buffer, 0, 0, null);
	}
	
	private double noise() {  
	    return Math.random()*0.5 + 0.5;  
	} 
	
	private double colorBlend(double scale, double dest, double src) {  
	    return (scale * dest + (1.0 - scale) * src);  
	} 
	
	 private  int clamp(int c)  
	    {  
	        return c > 255 ? 255 :( (c < 0) ? 0: c);  
	    } 

效果图如下:
在这里插入图片描述

图像卷积处理特效

在此例中,实现的图像卷积原理是拿一个3×3的矩阵对图片的每个像素点进行处理。而且要对每个像素点的RGB值单独处理。在本例中,我用的矩阵是
【-1,-1,-1】
【-1, 8 , -1】
【-1,-1,-1】
对图片进行处理,我将其存在了一个一维数组里面。改变里面的参数的话,得到的图形效果也不同。
代码如下

//图像卷积
	public void juanji(Graphics g) {
		
		int RGB[] = new int[9];
		int k[] = { -1, -1, -1, -1, 8, -1, -1, -1, -1 };
		for (int j = 1; j < data[0].length - 1; j++) {
			for (int i = 1; i < data.length - 1; i++) {
				RGB[0] = data[i - 1][j - 1];
				RGB[1] = data[i][j - 1];
				RGB[2] = data[i + 1][j - 1];
				RGB[3] = data[i - 1][j];
				RGB[4] = data[i][j];
				RGB[5] = data[i + 1][j];
				RGB[6] = data[i - 1][j + 1];
				RGB[7] = data[i][j + 1];
				RGB[8] = data[i][j + 1];
				int R = 0;
				int G = 0;
				int B = 0;
				for (int n = 0; n < 9; n++) {
					R += (((0x00ff0000 & RGB[n]) >> 16) * k[n]);
					G += (((0x0000ff00 & RGB[n]) >> 8) * k[n]);
					B += ((0xff & RGB[n]) * k[n]);
				}
				if (R > 255)
					R = 255;
				if (G > 255)
					G = 255;
				if (B > 255)
					B = 255;
				if (R < 0)
					R = 0;
				if (G < 0)
					G = 0;
				if (B < 0)
					B = 0;
				c = new Color(R, G, B);
				bg.setColor(c);
				bg.drawLine(j+120, i+80, j+120, i+80);
			}
		}
		g.drawImage(buffer, 0, 0, null);
	}

图片效果如下:
在这里插入图片描述
在卷积的基础上再做删改就可以得到素描或者浮雕的效果了。

沙画特效

小伙伴们应该都看到过沙画,下面这种特效就是实现沙画的效果。
沙画的实现主要是对下落规则的实现。
将图片的像素点进行2x2的分组,然后总共有九种下落的规则。
在下面叙述中,黑点代表沙子。
在这里插入图片描述
代码如下

	 //时间沙画
    public void TSpainting(Graphics g){
    	//数组color保存图像0,1信息
    	color = new int[buffer.getWidth()][buffer.getHeight()];
    
			
    	//将图像的黑白信息储存到 数组color中,黑为0,其他为1
    	for(int i=0;i<buffer.getHeight();i++)
			for(int j=0;j<buffer.getWidth();j++)
			{
				int RGB = buffer.getRGB(j, i);
				int R = (RGB>>16) & 0xff;
				int G = (RGB>>8) & 0xff;
				int B = RGB & 0xff;    
				int VAG = (int)(R+G+B)/3;
				
				if(VAG<30)
				color[j][i]=0;
				else
				color[j][i]=1;
			}
    	
    	//画n张图像,实现动态效果
    	for(int R=1;R<200;R++){
    		
    	if(R%2!=0)
    	{
    	//从(0,0)取2*2卷积,对数组color进行变换
    	for(int i=0;i<buffer.getHeight()-2;i+=2)
			for(int j=0;j<buffer.getWidth()-2;j+=2)
			{
				double p = Math.random();
				if((color[j][i]==1)&&(color[j+1][i]==0)&&(color[j][i+1]==0)&&(color[j+1][i+1]==0)){
					color[j][i]=0;
				    color[j+1][i]=0;
				    color[j][i+1]=1;
				    color[j+1][i+1]=0;
				}
				else if((color[j][i]==0)&&(color[j+1][i]==1)&&(color[j][i+1]==0)&&(color[j+1][i+1]==0)){
					color[j][i]=0;
				    color[j+1][i]=0;
				    color[j][i+1]=0;
				    color[j+1][i+1]=1;
				}
				else if((color[j][i]==1)&&(color[j+1][i]==0)&&(color[j][i+1]==1)&&(color[j+1][i+1]==0)){
					color[j][i]=0;
				    color[j+1][i]=0;
				    color[j][i+1]=1;
				    color[j+1][i+1]=1;
				}
				else if((color[j][i]==0)&&(color[j+1][i]==1)&&(color[j][i+1]==0)&&(color[j+1][i+1]==1)){
					color[j][i]=0;
				    color[j+1][i]=0;
				    color[j][i+1]=1;
				    color[j+1][i+1]=1;
				}
				else if((color[j][i]==0)&&(color[j+1][i]==1)&&(color[j][i+1]==1)&&(color[j+1][i+1]==0)){
					color[j][i]=0;
				    color[j+1][i]=0;
				    color[j][i+1]=1;
				    color[j+1][i+1]=1;
				}
				else if((color[j][i]==1)&&(color[j+1][i]==0)&&(color[j][i+1]==0)&&(color[j+1][i+1]==1)){
					color[j][i]=0;
				    color[j+1][i]=0;
				    color[j][i+1]=1;
				    color[j+1][i+1]=1;
				}
				else if((color[j][i]==1)&&(color[j+1][i]==1)&&(color[j][i+1]==0)&&(color[j+1][i+1]==0)&&(p<=0.8)){
					color[j][i]=0;
				    color[j+1][i]=0;
				    color[j][i+1]=1;
				    color[j+1][i+1]=1;
				}
				else if((color[j][i]==1)&&(color[j+1][i]==1)&&(color[j][i+1]==1)&&(color[j+1][i+1]==0)){
					color[j][i]=1;
				    color[j+1][i]=0;
				    color[j][i+1]=1;
				    color[j+1][i+1]=1;
				}
				else if((color[j][i]==1)&&(color[j+1][i]==1)&&(color[j][i+1]==0)&&(color[j+1][i+1]==1)){
					color[j][i]=0;
				    color[j+1][i]=1;
				    color[j][i+1]=1;
				    color[j+1][i+1]=1;
				}
			}
    	
    	//根据变化之后的数组color进行绘图
    	BufferedImage image = new BufferedImage(buffer.getWidth(), buffer.getHeight(), BufferedImage.TYPE_INT_ARGB);
		Graphics bg = image.getGraphics();
    	for(int i=0;i<buffer.getHeight();i++)
			for(int j=0;j<buffer.getWidth();j++)
			{
				
				if(color[j][i]==0)
				bg.setColor(Color.black);
				else if(color[j][i]==1)
				bg.setColor(Color.white);
				
				bg.drawLine(j+120, i+80, j+120, i+80);
			}
    	g.drawImage(image, 0, 0, null);
    	
    	}	
    	
    	else if(R%2==0)
    	{
    	//从(1,1)取2*2卷积,对数组color进行变换
    	for(int i=1;i<buffer.getHeight()-1;i+=2)
			for(int j=1;j<buffer.getWidth()-1;j+=2)
			{
				double p = Math.random();
				if((color[j][i]==1)&&(color[j+1][i]==0)&&(color[j][i+1]==0)&&(color[j+1][i+1]==0)){
					color[j][i]=0;
				    color[j+1][i]=0;
				    color[j][i+1]=1;
				    color[j+1][i+1]=0;
				}
				else if((color[j][i]==0)&&(color[j+1][i]==1)&&(color[j][i+1]==0)&&(color[j+1][i+1]==0)){
					color[j][i]=0;
				    color[j+1][i]=0;
				    color[j][i+1]=0;
				    color[j+1][i+1]=1;
				}
				else if((color[j][i]==1)&&(color[j+1][i]==0)&&(color[j][i+1]==1)&&(color[j+1][i+1]==0)){
					color[j][i]=0;
				    color[j+1][i]=0;
				    color[j][i+1]=1;
				    color[j+1][i+1]=1;
				}
				else if((color[j][i]==0)&&(color[j+1][i]==1)&&(color[j][i+1]==0)&&(color[j+1][i+1]==1)){
					color[j][i]=0;
				    color[j+1][i]=0;
				    color[j][i+1]=1;
				    color[j+1][i+1]=1;
				}
				else if((color[j][i]==0)&&(color[j+1][i]==1)&&(color[j][i+1]==1)&&(color[j+1][i+1]==0)){
					color[j][i]=0;
				    color[j+1][i]=0;
				    color[j][i+1]=1;
				    color[j+1][i+1]=1;
				}
				else if((color[j][i]==1)&&(color[j+1][i]==0)&&(color[j][i+1]==0)&&(color[j+1][i+1]==1)){
					color[j][i]=0;
				    color[j+1][i]=0;
				    color[j][i+1]=1;
				    color[j+1][i+1]=1;
				}
				else if((color[j][i]==1)&&(color[j+1][i]==1)&&(color[j][i+1]==0)&&(color[j+1][i+1]==0)&&(p<=0.8)){
					color[j][i]=0;
				    color[j+1][i]=0;
				    color[j][i+1]=1;
				    color[j+1][i+1]=1;
				}
				else if((color[j][i]==1)&&(color[j+1][i]==1)&&(color[j][i+1]==1)&&(color[j+1][i+1]==0)){
					color[j][i]=1;
				    color[j+1][i]=0;
				    color[j][i+1]=1;
				    color[j+1][i+1]=1;
				}
				else if((color[j][i]==1)&&(color[j+1][i]==1)&&(color[j][i+1]==0)&&(color[j+1][i+1]==1)){
					color[j][i]=0;
				    color[j+1][i]=1;
				    color[j][i+1]=1;
				    color[j+1][i+1]=1;
				}
			}
    	
    	//根据变化之后的数组color进行绘图
    	BufferedImage image = new BufferedImage(buffer.getWidth(), buffer.getHeight(), BufferedImage.TYPE_INT_ARGB);
		Graphics bg = image.getGraphics();
    	for(int i=0;i<buffer.getHeight();i++)
			for(int j=0;j<buffer.getWidth();j++)
			{
				
				if(color[j][i]==0)
				bg.setColor(Color.BLACK);
				else if(color[j][i]==1)
					bg.setColor(Color.WHITE);
					
				
				bg.drawLine(j+120, i+80, j+120, i+80);
			}
    	g.drawImage(image, 0, 0, null);
    	
    	}	
   	
}
}

图片如下
在这里插入图片描述

摄像头

//摄像
	public void cam(Graphics g) {
		//获取摄像头
		  Webcam cam = Webcam.getDefault();
		  //设置摄像头的大小
		  cam.setViewSize(WebcamResolution.VGA.getSize());
		  //打开摄像头
		  cam.open();
		  
		  //获取图像
		  for(int i=0;i<100;i++) {
			//  long start = System.currentTimeMillis();
			  BufferedImage buffer = cam.getImage();
			ImgToArr(buffer);
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
					//BlackWhite(g);
					BlackWhite(g);
						//System.out.println(System.currentTimeMillis()-start);
			  
		  }
		
		  //关闭摄像头
		  cam.close(); 
		
	}
	//图片转数组
public void ImgToArr(BufferedImage img) {
	data = new int[img.getHeight()][img.getWidth()];
    for(int i=0;i<img.getHeight();i++) {
    	for(int j=0;j<img.getWidth();j++) {
    		data[i][j]=img.getRGB(j, i);
    	}
    }
}

我会把我的代码上传到我的资源之中,有需要的小伙伴可以下载,里面包括调用摄像头,可以实现比如摄像头显示黑白效果或者底片啊旧时光效果等等。

猜你喜欢

转载自blog.csdn.net/qq_44807642/article/details/98205162