java入门之 美图相机(原图、灰度、二值化、马赛克、融合、轮廓获取)

编写美图相机时,我们首先需要了解图片再计算机中的存储形式,详情可见http://t.csdn.cn/MgOfO

目录

<1>创建显示图片的主界面

1.添加窗体,用数列添加按钮,设置窗体可视化,添加主函数

 2.先创建对象,再为按钮添加监听器

<2> 实现接口,添加监听事件

<3> 创建”ImageTool“类,绘图时进行调用

1.绘制原图

2.绘制灰度图片

3.绘制二值化图片

4.绘制马赛克图片

<1>创建显示图片的主界面

1.添加窗体,用数列添加按钮,设置窗体可视化,添加主函数

import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;

public class PictureUI {
	public void showUI() {
		JFrame jf = new JFrame("图像处理");
		jf.setSize(900,600);
		jf.setDefaultCloseOperation(3);
		jf.setLayout(new FlowLayout());
//		FlowLayout flow = new FlowLayout();
//		jf.setLayout(flow);
		
		//创建按钮对象
		String[] strs = {"原图","灰度","二值化","像素化"};
		for(int i = 0;i < strs.length;i++) {
			JButton btn = new JButton(strs[i]);
			jf.add(btn);
		
			
		jf.setVisible(true);
		
		}
	}
	public static void main (String[] args) {
		new PictureUI().showUI();
	}
}

 2.先创建对象,再为按钮添加监听器

        //创建监听器对象
		ImageListener imgl = new ImageListener();
		//为按钮添加监听器
		btn.addActionListener(imgl);

<2> 实现接口,添加监听事件

在监听事件中,通过判断所获取的字符串不同,而执行相应的代码。为了使代码更加简洁明了,我们可以选择创建一个类(这里我们称它为ImageTool),当需要绘制图形时,通过调用类中的相应方法绘制出图形。

    ImageTools imgtools = new ImageTools();
	Graphics g;
	int[][] imageArr;
	
	{//代码块 创建对象的时候就执行 初始化的方法调用
		String path = "C:\\Users\\asus\\Desktop\\th.jpeg";
	 // 传入图片路径,得到图片的像素二维数组
		imageArr = imgtools.getImagePiexArry(path);
	}
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ImageListener implements ActionListener{

	@Override
	public void actionPerformed(ActionEvent e) {
		//获取按钮上的字符串
		String btnStr = e.getActionCommand();
		System.out.println("点击了" + btnStr);	
	//根据字符串绘制相关图片
		switch(btnStr) {
			case"原图":
                //绘制图片
				imgtools.drawImage(imageArr,g);
				break;
			case"灰度":
				break;
			case"二值化":
				break;
			case"马赛克":
				break;
		}
    }

}

<3> 创建”ImageTool“类,绘图时进行调用

绘制图片时,我们需要先获得图片的地址(可以通过参数传递过来);获得图片后,我们将它存入数组中(图片是由一个个的像素点组成,也就是失真后的图片)那么我们可以将图片的长和宽看作一个二维数组(图片的第一行看作一维数组,而第一行的第一个格子含有多个像素点(这也可以看作一个一维数组,即一个一维数组中包含着另一个一维数组,这样的结构就称作二维数组);最后,通过for循环的方式将像素点存入数组中,绘制图片时重新遍历数组即可。

	int x = 100;
	int y = 100;
	
/*
 * 根据图片来获得图片的二维数组
 */
	public int[][] getImagePiexArry(String path){
		File file = new File(path);
		BufferedImage buffimg = null;
		try {
			buffimg = ImageIO.read(file);
		}catch(IOException e) {
			throw new RuntimeException(e);
		}
		
		//buffimg 宽 高 像素值
		int width = buffimg.getWidth();
		int height = buffimg.getHeight();
		//创建二维数组
		int[][] imgArr = new int[width][height];
		//遍历循环将所有的像素值存入数组中
		for(int i = 0;i < imgArr.length;i++) {
			for(int j = 0;j < imgArr[i].length;j++) {
				imgArr[i][j] = buffimg.getRGB(i, j);
			}
		}
		return imgArr;
	}

1.绘制原图

    public void drawImage(int[][] imgArr,Graphics g) {
		for(int i = 0;i < imgArr.length;i++) {
			for(int j = 0;j < imgArr[i].length;j++) {
				int pixnum = imgArr[i][j];
				Color color = new Color(pixnum);
				g.setColor(color);
				g.fillRect(x+i, y+j, 1, 1);
			}
		}
	}

2.绘制灰度图片

灰度的处理,通常是让图片的R、G、B三个值相等。

法一:均值法(取R、G、B三个值的平均值)

法二:最大最小平均法(取R、G、B中的两个最大值进行均值)

法二:加权平均法(R、G、B三个值✖不同的数,具体可百科)

    public void drawGrayImage(int[][] imageArr,Graphics g) {
		for(int i = 0;i < imageArr.length;i++) {
			for(int j = 0;j < imageArr[i].length;j++) {
				int pixnum = imageArr[i][j];
				//将像素拆开
				int red = (pixnum >> 16)&255;
				int green = (pixnum >> 8)&255;
				int blue = (pixnum >> 0)&255;
				//灰度运算(R=G=B)
				int gray = (red + green + blue)/3;
				Color color = new Color(gray,gray,gray);
				g.setColor(color);
				//绘制图形
				g.fillRect(x+i,y+j,1,1);
			}
		}
	}

3.绘制二值化图片

二值图片是只有0(代表黑色)和255(代表白色)的图片。先计算出灰度值,通过设置的阈值判定每个像素点的灰度值应为0还是255。

    public void drawBinaryImage(int[][] imageArr,Graphics g) {
		for(int i = 0;i < imageArr.length;i++) {
			for(int j = 0;j < imageArr[i].length;j++) {
				int pixnum = imageArr[i][j];
				//将像素拆分
				int red = (pixnum >> 16)&255;
				int green = (pixnum >> 8)&255;
				int blue = (pixnum >> 0)&255;
				//计算灰度值
				int gray = (red+green+blue)/3;
				//利用灰度值做二分法
				if(gray<125) {
					g.setColor(Color.black);
				}else {
					g.setColor(Color.white);
				}
				g.fillRect(x+i, y+j, 1, 1);
			}
		}
	}

4.绘制马赛克图片

所谓的马赛克,通俗理解就是将原来的一个像素点绘制一次,变成多个像素点绘制一次,如下左图为遍历二维数组时,隔十个读取并绘制一次;右图为隔十个遍历一次二维数组,同时在遍历二维数组中的一维数组时也隔十个进行遍历。

    public void drawMosaicImage(int[][] imageArr,Graphics g) {
		for(int i = 0;i < imageArr.length;i+=10) {
			for(int j = 0;j < imageArr[i].length;j++) {
				int pixnum = imageArr[i][j];
				//均值法
				
				Color color = new Color(pixnum);
				g.setColor(color);
				g.fillRect(x+i, y+j, 10, 10);
			}
		}
	}

5.图像融合

图像融合是利用两张图片的每个像素点进行颜色的均值运算。那么要想将两张图片融合在一起,首先我们需要添加“图片融合”按钮,其次获得第二张图片的图片路径建立数组,将图片路径传递到数组中;当点击按钮时,执行图片融合的相关代码。在ImageTools中加入图片融合代码(也就是进行图片的融合绘制)。

    int[][] imageArr;
	int[][] imageArr2;
	
	{//代码块 创建对象的时候就执行 初始化的方法调用
		String path = "D:\\it\\课程\\09-30 美图相机\\th.jpeg";
		String path2 = "D:\\it\\课程\\09-30 美图相机\\图片2.jpeg";
	 // 传入图片路径,得到图片的像素二维数组
		imageArr = imgtools.getImagePiexArry(path);
		imageArr2 = imgtools.getImagePiexArry2(path2);
        case"融合":
				imgtools.drawmixImage2(imageArr,imageArr2, g);
				break;

在ImageTools中,对于图片融合代码,首先,我们需要将第一张图片和第二张图片的的数组通过参数的形式传递过来,同时也要把画笔g传递过来

public void drawmixImage2(int[][] imageArr2,int[][] imageArr,Graphics g) {
}

其次两张图片的融合需要考虑到我们在遍历数组时的图片 “宽”,“高”必须是最小的(两张图片叠在一起的重合之处融合在一起,如果所选取的宽高不是最小的会出现“溢出”报错现象)。那么我们用一个三元运算进行判断两张图片的最小宽和最小高

        int W = imageArr2.length < imageArr.length ? imageArr2.length : imageArr.length;
		int H = imageArr2[0].length < imageArr[0].length ? imageArr2[0].length : imageArr[0].length;
		

最后,我们将两个数组的像素值分别取出,并同时将他们拆分成RGB模式。将两张图片各自的RGB进行均值运算,再将均值运算的结果绘制出来。完整代码如下:

/*
	 * 融合
	 */
	public void drawmixImage2(int[][] imageArr2,int[][] imageArr,Graphics g) {
		int W = imageArr2.length < imageArr.length ? imageArr2.length : imageArr.length;
		int H = imageArr2[0].length < imageArr[0].length ? imageArr2[0].length : imageArr[0].length;
		for(int i = 0;i < W;i++) {
			for(int j = 0;j < H;j++) {
						int pixnum1 = imageArr[i][j];
						int pixnum2 = imageArr2[i][j];
						//均值法
						int red1 = (pixnum1 >> 16)&255;
						int green1 = (pixnum1 >> 8)&255;
						int blue1 = (pixnum1 >> 0)&255;
						
						int red2 = (pixnum2 >> 16)&255;
						int green2 = (pixnum2 >> 8)&255;
						int blue2 = (pixnum2 >> 0)&255;
						
						int pix1 = (red1 + red2)/2;
						int pix2 = (green1 + green2)/2;
						int pix3 = (blue1 + blue2)/2;
						//均值法
						Color color = new Color(pix1,pix2,pix3);
						g.setColor(color);
						g.fillRect(x+i, y+j, 10, 10);
				
			}
		}
	}

6.轮廓获取(边缘化)

边缘化我们可以理解为,获取物体的轮廓,而物体的轮廓在我们眼中也就是所谓的界限,界限的左边与右边,上边与下边都存在明显差距(在颜色上的差异,也就是像素点的颜色差异)。那么我们需要获得图片中房子的轮廓,只需要在原图的基础上添加一个循环,进行判断前后像素点的差异即可(像素点的差异越小,画出来的图片也就越精细)

下图为某个像素点的前后左右的像素差值>15所画出的图片

注意,建议在灰度图的基础上进行,若用RGB值直接进行比较是不可行的(想一想RGB在二进制中的存储形式,若红色/绿色仅相差1,那么用RGB进行比较则差距过大)

/**
	 * 边缘化
	 */
	public void marginalization(int[][] imageArr,Graphics g) {
		for(int i = 0;i < imageArr.length-1;i++) {
			for(int j = 0;j < imageArr[i].length-1;j++) {
				int pixnum = imageArr[i][j];
				//将像素拆开
				int red = (pixnum >> 16)&255;
				int green = (pixnum >> 8)&255;
				int blue = (pixnum >> 0)&255;
				
				int pixnum1 = imageArr[i+1][j+1];
				//将像素拆开
				int red1 = (pixnum1 >> 16)&255;
				int green1 = (pixnum1 >> 8)&255;
				int blue1 = (pixnum1 >> 0)&255;
				//灰度运算(R=G=B)
				int gray = (red + green + blue)/3;
				int gray1 = (red1 + green1 + blue1)/3;
				int colorgray = 255<<24|gray<<16|gray<<8|gray;
				//Color color = new Color(gray,gray,gray);
				
				if(Math.abs(gray-gray1)>15) {
					g.setColor(Color.black);
				}else {
					g.setColor(Color.white);
				}
				g.fillRect(x+i,y+j,1,1);
			}
		}
	}

 

以上就是有关java的美图相机内容!感谢阅读! 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值