java bufferedimage_切割1张图片成很多小图片 批量文件命名 java 脚本

参考:java中图片与二维数组的互相转换,ARGB与RGB的互相转换_HJ他说他在笑_新浪博客

JAVA实现本地文件批量重命名 - 景向后山的博客 - CSDN博客

起因:帮学长预处理做一个图像识别的卷积神经网络的训练集。

首先学长发来200张658*492的tiff图片文件。我一开始直接用java进行读取,一直读取不了,后来才发现jdk源码是不支持tiff图片文件的读取的,需要引入其它的jar包,感觉比较麻烦。所以我直接下载了一个图片转换软件进行转换:

635746860717894ba9fba603fc1fe148.png

这类成型的软件还是比较好用的,有批处理能力,比起网上在线的转换好多了。后面发现还可以直接使用matlab或者python进行转换,调调api就可以了,这样就不用下载软件了。

然后我就全部转换成了jpg文件。

刚开始想着不太熟悉,所以先转一张图片试试。

总体思路:我比较熟悉数组操作图片。我已打算把图片转化为数组,然后进行数组的分割,然后再把小数组转化为图片。

1.首先先读取图片。

public static BufferedImage readImage(String imageFile) {
		File file = new File(imageFile);
		BufferedImage bf = null;
		try {
			bf = ImageIO.read(file);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return bf;
	}

这里是使用了bufferedimge进行图片的存储,java一般都是使用它来操作处理图片。

ImageIO.read(file) 读取图片文件。

2.图片转化为数组

public static int[][] convertImageToArray(BufferedImage bf) {
		// 获取图片宽度和高度
		int width = bf.getWidth();
		int height = bf.getHeight();
		// 将图片sRGB数据写入一维数组
		int[] data = new int[width * height];
		bf.getRGB(0, 0, width, height, data, 0, width);
		// 将一维数组转换为为二维数组
		int[][] rgbArray = new int[height][width];
		for (int i = 0; i < height; i++)
			for (int j = 0; j < width; j++)
				rgbArray[i][j] = data[i * width + j];
		return rgbArray;
	}

函数输入为bufferedimage,返回为一个int类型的二维数组。数组里的值表示这个像素点的RGB值,入如果不理解的可以另外了解。

这里是有个api:bf.getRGB(0, 0, width, height, data, 0, width); 它的作用是读取bufferedimage的像素值存取进一个一维数组里面,这是封装好了的。然后把一维数组按照计划转成二维数组。

3.我这里先不进行切割,直接再把二维数组转成图片,验证代码是否正确。大家可以输出二维数组进行观察理解。

public static void writeImageFromArray(String imageFile, String type, int[][] rgbArray) {
		// 获取数组宽度和高度
		int width = rgbArray[0].length;
		int height = rgbArray.length;
		// 将二维数组转换为一维数组
		int[] data = new int[width * height];
		for (int i = 0; i < height; i++)
			for (int j = 0; j < width; j++)
				data[i * width + j] = rgbArray[i][j];
		// 将数据写入BufferedImage
		BufferedImage bf = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
		bf.setRGB(0, 0, width, height, data, 0, width);
		// 输出图片
		try {
			File file = new File(imageFile);
			ImageIO.write((RenderedImage) bf, type, file);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

有了前面的基础,相信大家非常好理解这段代码了,我验证成功,所以没问题。

4.看主函数。

public static void main(String[] args) {
		// 读取图片到BufferedImage
		BufferedImage bf = readImage("d:jpgfile1.jpg");// 这里写你要读取的绝对路径+文件名
		// 将图片转换为二维数组
		int[][] rgbArray1 = convertImageToArray(bf);
		// 输出图片到指定文件
		writeImageFromArray("d:2.jpg", "jpg", rgbArray1);// 这里写你要输出的绝对路径+文件名
		System.out.println("图片输出完毕!");
	}

操作成功,没什么问题。

然后我开始进行我的批量图片切割:

由于492*658不合适28*28的匹配,所以我先整体切割成476*644的图,然后一张图片就会出来23 * 17=391张图片 200张图片一共分割成78200张小图片。

我另外封装了切割图片大小的函数:

public static BufferedImage resize(BufferedImage bi) {
		BufferedImage subimage = bi.getSubimage(0, 0, 644, 476);
		return subimage;
	}

这个函数的关键就是bi.getSubimage,它就是直接截取图片,java的0,0图片坐标是在左上角。大家理解一下动动手就可以了。

这里使用了ImageToArrayUtils工具类,这是参考前面链接里的工具类写的。

也就是封装了操作图片数组的函数,这样调用起来比较方便。

我的完整代码如下:

public static void main(String[] args) {
		int k = 0;
		for (int fff = 0; fff < 200; fff++) {
			// if (fff == 6 || fff == 26 || fff == 38 || fff == 59 || fff == 61
			// || fff == 64)
			// continue; 这段代码是我后来发现里面图片的命名是会缺少的,并不是完整的,所以后面进行了批量的文件重命名
			System.out.println(fff);
			BufferedImage bi = ImageToArrayUtils.readImage("d:jpgfile" + fff + ".jpg");
			bi = ImageToArrayUtils.resize(bi);
			// 将图片转换为二维数组

			int[][] rgbArray = ImageToArrayUtils.convertImageToArray(bi);
			// 高476 宽644
			System.out.println(rgbArray.length + " " + rgbArray[0].length);

			BufferedImage subimage = null;
			int[][] imageToArray = null;
			for (int i = 0; i < rgbArray[0].length - 1; i = i + 28) {
				for (int j = 0; j < rgbArray.length - 1; j = j + 28) {
					// System.out.println(i + " " + j);
					subimage = bi.getSubimage(i, j, 28, 28);
					imageToArray = ImageToArrayUtils.convertImageToArray(subimage);
					ImageToArrayUtils.writeImageFromArray("d:jpgsonfile" + k++ + ".jpg", "jpg", imageToArray);
				}

			}
		}
	}

首先前一部分是读取图片里的每一张图片,然后转化为二维数组,后来发现其实没必要这样的,用file类就可以把文件名全部存取进数组中,这样更方便,当时一下子没想到。

然后就是两个for循环,巧妙地利用getSubimage进行获取小图片,然后再将图片转化为数组,然后再将数组转化成图片。这里是使用api方便,所以这样写,大家可以直接将获取的小图片进行存储即可,没必要再转化成数组,有相应的api左这件事情。

这个工具类和前面的差不多,之类拿出来吧:

public class ImageToArrayUtils {
	public static BufferedImage readImage(String imageFile) {

		File file = new File(imageFile);

		BufferedImage bf = null;

		try {

			bf = ImageIO.read(file);

		} catch (IOException e) {

			e.printStackTrace();

		}

		return bf;

	}

	public static void writeImageFromBufferedImage(String imageFile, String type, BufferedImage bf) {

		File file = new File(imageFile);

		try {

			ImageIO.write((RenderedImage) bf, type, file);

		} catch (IOException e) {

			e.printStackTrace();

		}

	}

	public static int[][] convertImageToArray(BufferedImage bf) {

		// 获取图片宽度和高度

		int width = bf.getWidth();

		int height = bf.getHeight();
		// System.out.println("宽=" + width + " 高=" + height);

		// 将图片sRGB数据写入一维数组

		int[] data = new int[width * height];

		bf.getRGB(0, 0, width, height, data, 0, width);

		// 将一维数组转换为为二维数组

		int[][] rgbArray = new int[height][width];

		for (int i = 0; i < height; i++)

			for (int j = 0; j < width; j++)

				rgbArray[i][j] = data[i * width + j];

		return rgbArray;

	}

	public static int[][] convertImageToArrayByCoordinate(BufferedImage bf, int startX, int startY, int outWidth,
			int outHeight) {

		// 获取图片宽度和高度

		int width = bf.getWidth();

		int height = bf.getHeight();

		// 判断截取区域是否大于图片

		if (outWidth + startX > width || outHeight + startY > height)

			throw new IllegalArgumentException("截取区域大于图片");

		// 将图片sRGB数据写入一维数组

		int[] data = new int[outWidth * outHeight];

		bf.getRGB(startX, startY, outWidth, outHeight, data, 0, outWidth);

		// 将一维数组转换为为二维数组

		int[][] rgbArray = new int[outHeight][outWidth];

		for (int i = 0; i < outHeight; i++)

			for (int j = 0; j < outWidth; j++)

				rgbArray[i][j] = data[i * outWidth + j];

		return rgbArray;

	}

	public static void writeImageFromArray(String imageFile, String type, int[][] rgbArray) {

		// 获取数组宽度和高度

		int width = rgbArray[0].length;

		int height = rgbArray.length;

		// 将二维数组转换为一维数组

		int[] data = new int[width * height];

		for (int i = 0; i < height; i++)

			for (int j = 0; j < width; j++)

				data[i * width + j] = rgbArray[i][j];

		// 将数据写入BufferedImage

		BufferedImage bf = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);

		bf.setRGB(0, 0, width, height, data, 0, width);

		// 输出图片

		try {

			File file = new File(imageFile);

			ImageIO.write((RenderedImage) bf, type, file);

		} catch (IOException e) {

			e.printStackTrace();

		}

	}

	public static int[] convertARGBToRGB(int ARGB) {

		int[] rgb = new int[3];

		rgb[0] = (ARGB & 0xff0000) >> 16;

		rgb[1] = (ARGB & 0xff00) >> 8;

		rgb[2] = (ARGB & 0xff);

		return rgb;

	}

	public static int convertRGBToARGB(int r, int g, int b) {
		int color = ((0xFF << 24) + (r << 16) + (g << 8) + b);
		return color;
	}

	public static BufferedImage resize(BufferedImage bi) {
		BufferedImage subimage = bi.getSubimage(0, 0, 644, 476);
		return subimage;
	}

}

然后就ok完事了。

然后说一下文件的批量重命名:

这个是我发现名字不好读取,所以想写个脚本批量修改:参考的链接贴在上面:

public class ChangeName2 {
	public static String[] getFileName(String path) {
		File file = new File(path);
		String[] fileName = file.list();
		return fileName;
	}

	public static void renameFile(String path, String oldname, String newname) {
		if (!oldname.equals(newname)) {// 新的文件名和以前文件名不同时,才有必要进行重命名
			File oldfile = new File(path + "" + oldname);
			File newfile = new File(path + "" + newname);
			if (!oldfile.exists()) {
				return;// 重命名文件不存在
			}
			if (newfile.exists())// 若在该目录下已经有一个文件和新文件名相同,则不允许重命名
				System.out.println(newname + "已经存在!");
			else {
				oldfile.renameTo(newfile);
			}
		} else {
			System.out.println("新文件名和旧文件名相同...");
		}
	}

	public static void main(String[] args) {
		String[] fileName = getFileName("d:jpgfile");// <span
														// style="font-family:
														// Arial,
														// Helvetica,
														// sans-serif;">此处修改为你的本地路径</span>
		for (int i = 0; i < fileName.length; i++) {
			renameFile("d:jpgfile", fileName[i], i + ".jpg");// cx修改为你要修改的文件名格式
		}
	}

}

这个函数经过测试,没啥毛病。主要都是文件类的api都写得很不错了,重命名啥的都有,直接调用就行了。

下面是缺少6.tiff的

4956c00e95f3897ecc3d60df827029ee.png

下面是重命名后的:

f9e2979bdc53391bd824aa5e2b0bf174.png

效果不错。

然后看一下我最后切割出来的成果:

dc6dae82bd07e48437bc82e30c136284.png

基本上算把训练集做好了。

学长说使用matlab和python处理图片会方便很多,我也是想熟悉一下java在这方面的api。所以在知乎上记录一下自己的收获。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值