Java用BufferedImage处理图片实例

article/2025/10/9 10:49:32

       最近,项目中需要对图片进行处理。实现的方式当然有很多种,这里,我使用了Java的BufferedImage进行了实现。由于对图片的不熟悉,实现的时候费了点儿劲,这里记录一下,以备后用。

        场景描述:其实问题很简单,有一类混淆了的图片,我要将其还原。中间需要将图片切开,然后在重新组装。组装成跟原来一样大小的图片。中间不可以缩放比例,不可以裁剪丢失。

        也就是说:我们要将图1这样的图片,将其处理成图2和图3这样。

图1

 

图2
图3

没有很复杂的东西,关键就是一个对图片熟悉的过程,实现代码如下:

package com.lzq.images;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;/*** lzq* 滑块图片处理*/
public class DealImages {private static final List<Integer> drawImageCoor = Arrays.asList(22, 9, 21, 19, 14, 2, 6, 8, 3, 12, 15, 23, 5, 4, 7, 17, 18, 20, 10, 13, 25, 11, 0, 1, 16, 24);/*切割后图片的长度*/private static final int width = 20;/*切割后图片的宽*/private static final int height = 80;public static void main(String[] args) {BufferedImage bi = getImageFromFile("D:\\imageFile\\slide1.png");makeDrawImage(bi,BufferedImage.TYPE_INT_ARGB,"D:\\imageFile\\result1.png");makeDrawImage(bi,BufferedImage.TYPE_INT_RGB,"D:\\imageFile\\result2.png");}/*** 图片来源于本地* @param path* @return*/static BufferedImage getImageFromFile(String path){BufferedImage bi = null;try {bi = ImageIO.read(new FileInputStream(path));} catch (IOException e) {e.printStackTrace();}return bi;}/*** 图片来源于url* @param url* @return*/static BufferedImage getImageFromUrl(String url){BufferedImage bi = null;try {// 读取源图像URL bgPicUrl = new URL(url);bi = ImageIO.read(bgPicUrl);} catch (IOException e) {e.printStackTrace();}return bi;}/*** 图片处理* @param bi* @param bufferedImageType* @param resultPath* @return*/static BufferedImage makeDrawImage(BufferedImage bi, int bufferedImageType,String resultPath){BufferedImage imageNew = null;try {List<List<ImageInfo>> lsResult = cutImage(bi);List<ImageInfo> lsImage = new ArrayList<>();//分别横向合并lsImage.add(new ImageInfo(0,0,mergeImage(lsResult.get(0), TypeEnum.LIE,bufferedImageType)));lsImage.add(new ImageInfo(0,height,mergeImage(lsResult.get(1), TypeEnum.LIE,bufferedImageType)));//纵向合并imageNew = mergeImage(lsImage, TypeEnum.STAND,bufferedImageType);ImageIO.write(imageNew, "png", new File(resultPath));} catch (Exception e) {e.printStackTrace();}return imageNew;}/*** 图像切割(按指定起点坐标和宽高切割)* @param bi 源图像*/private static List<List<ImageInfo>> cutImage(BufferedImage bi) {List<List<ImageInfo>> lsResult = new ArrayList<>();List<ImageInfo> images1 = new ArrayList<>();List<ImageInfo> images2 = new ArrayList<>();try {int srcHeight = bi.getHeight(); // 源图宽度int srcWidth = bi.getWidth(); // 源图高度for (int i = 0; i < drawImageCoor.size(); i++) {int drawImg = drawImageCoor.get(i);int half = drawImageCoor.size() / 2;int x = (drawImg % half) * 20;if (drawImg == 0) {x = 0;}int y = (int) Math.floor(drawImg / half) * 80;int sx = (i % half) * 20;if (i == 0)sx = 0;int sy = (int) Math.floor(i / half) * 80;Image image = bi.getScaledInstance(srcWidth, srcHeight, Image.SCALE_DEFAULT);// 四个参数分别为图像起点坐标和宽高// 即: CropImageFilter(int x,int y,int width,int height)
//                System.out.println("sx="+sx+";sy="+sy+";x="+x+";y="+y);ImageFilter cropFilter = new CropImageFilter(sx, sy, width, height);Image img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(),cropFilter));BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);Graphics g = tag.getGraphics();g.drawImage(img, 0, 0, width, height, null); // 绘制切割后的图g.dispose();if (y>0){images2.add(new ImageInfo(x,y,tag));}else {images1.add(new ImageInfo(x,y,tag));}}Collections.sort(images1);Collections.sort(images2);lsResult.add(images1);lsResult.add(images2);} catch (Exception e) {e.printStackTrace();}return lsResult;}/*** 图片拼接 (注意:必须两张图片长宽一致哦)* @param imageInfos 要拼接的文件列表* @param type 横向拼接, 2 纵向拼接*/private static BufferedImage mergeImage(List<ImageInfo> imageInfos, TypeEnum type, int bufferedImageType) {BufferedImage imageNew;int len = imageInfos.size();if (len < 1) {throw new RuntimeException("图片数量小于1");}BufferedImage[] images = new BufferedImage[len];int[][] ImageArrays = new int[len][];for (int i = 0; i < len; i++) {try {images[i] = imageInfos.get(i).getBufferedImage();} catch (Exception e) {throw new RuntimeException(e);}int width = images[i].getWidth();int height = images[i].getHeight();ImageArrays[i] = new int[width * height];ImageArrays[i] = images[i].getRGB(0, 0, width, height, ImageArrays[i], 0, width);}int newHeight = 0;int newWidth = 0;for (int i = 0; i < images.length; i++) {// 横向if (type == TypeEnum.LIE) {newHeight = newHeight > images[i].getHeight() ? newHeight : images[i].getHeight();newWidth += images[i].getWidth();} else if (type == TypeEnum.STAND) {// 纵向newWidth = newWidth > images[i].getWidth() ? newWidth : images[i].getWidth();newHeight += images[i].getHeight();}}if (type == TypeEnum.LIE && newWidth < 1) {return null;}if (type == TypeEnum.STAND && newHeight < 1) {return null;}// 生成新图片try {/** BufferedImage.TYPE_INT_RGB 生成原图* BufferedImage.TYPE_INT_ARGB 严格按照图盘文件生成* */
//            imageNew = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);imageNew = new BufferedImage(newWidth, newHeight, bufferedImageType);int height_i = 0;int width_i = 0;for (int i = 0; i < images.length; i++) {if (type == TypeEnum.LIE) {imageNew.setRGB(width_i, 0, images[i].getWidth(), newHeight, ImageArrays[i], 0, images[i].getWidth());width_i += images[i].getWidth();} else if (type == TypeEnum.STAND) {imageNew.setRGB(0, height_i, newWidth, images[i].getHeight(), ImageArrays[i], 0, newWidth);height_i += images[i].getHeight();}}} catch (Exception e) {throw new RuntimeException(e);}return imageNew;}/*** 两张图片,比较滑动点* @param testphoto 滑动图* @param contrasphoto 原图* @return*/public static int slideLength(BufferedImage testphoto, BufferedImage contrasphoto){int contras_rgb[] = new int[3];int test_rgb[] = new int[3];int k = 0;//		int contraswidth = contrasphoto.getWidth();
//		int contrasheight = contrasphoto.getHeight();int testwidth = testphoto.getWidth();int testheight = testphoto.getHeight();for (int i = 0; i < testwidth; i++) {for (int j = 0; j < testheight; j++) {int pixel1 = contrasphoto.getRGB(i, j);int pixle2= testphoto.getRGB(i, j);contras_rgb[0] = (pixel1 & 0xff0000) >> 16;  //将值转化成16进制contras_rgb[1] = (pixel1 & 0xff00) >> 8;contras_rgb[2] = (pixel1 & 0xff);test_rgb[0] = (pixle2 & 0xff0000) >> 16;test_rgb[1] = (pixle2 & 0xff00) >> 8;test_rgb[2] = (pixle2 & 0xff);int Difference_R = Math.abs(contras_rgb[0]-test_rgb[0]);  //相减并且求绝对值int Difference_G= Math.abs(contras_rgb[1]-test_rgb[1]);int Difference_B= Math.abs(contras_rgb[2]-test_rgb[2]);//System.out.println("第"+j+"次:"+Math.abs(Difference));final int R = 35; //35final int L = 130;int Q = Difference_R+Difference_G+Difference_B;if (Difference_R>30 || Difference_G>30 ||Difference_B>30){return i;}}}return k;}/*** 滑块滑动距离* @param bi* @return*/public static int slideLength(BufferedImage bi){System.out.println(bi.getWidth());int x=bi.getWidth();for (int i = 0; i < bi.getWidth(); i++) {for (int j = 0; j < bi.getHeight(); j++) {int cl = bi.getRGB(i, j);if(cl>250*250*250) {bi.setRGB(i, j, (new Color(0f,0f,0f)).getRGB());if(x>i&&bi.getRGB(i+5, j+20)>250*250*250 ) {x=i;}}}}return x;}/*** 拼接图片方式类型*/enum TypeEnum{LIE(1,"横着"),STAND(2,"竖着");private int code;private String desc;TypeEnum(int code, String desc){this.code = code;this.desc = desc;}}/*** 图片信息单元存储*/static class ImageInfo implements Comparable<ImageInfo> {private int x; //横坐标private int y; //纵坐标private BufferedImage bufferedImage;public ImageInfo(int x, int y, BufferedImage bufferedImage) {this.x = x;this.y = y;this.bufferedImage = bufferedImage;}@Overridepublic int compareTo(ImageInfo image) {return this.x - image.getX();}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}public BufferedImage getBufferedImage() {return bufferedImage;}}
}

        总结:该实现,还包括对图片处理的一系列功能:

            对图片的切割、重组;

             生成滑块图;

             生成真实原图;

             滑块图缺失部分的位置比较。


http://chatgpt.dhexx.cn/article/p0ChqOjP.shtml

相关文章

彻底理解ThreadLocal、ITL、TTL

懒人改变了世界,简化了世界,却隐瞒了世界的真相. 大家好,今天跟大家剖析一下ThreadLocal. 文章目录 痛苦的回忆抛几个问题前奏铺垫正片详解 痛苦的回忆 不知道大家有没有面向JDBC编程的经历.如果有的话,可以回想一下那是一种怎样的体验;如果没有,也可以假装有这样的经历,然…

【转】线上内存溢出分析

状况描述&#xff1a; 最近项目新打的版本&#xff0c;过不了多长时间&#xff0c;项目就会挂掉。状况就是处于一种假死的状态。索引查询都很慢&#xff0c;几乎进行不了任何操作&#xff0c;慢慢卡死。 然后我们再发版时&#xff0c;只能基于之前打好的war包&#xff0c;替换或…

SQL Server数据库基础的级联删除、级联更新与三层架构之窥

一、定义&#xff1a; 级联删除是指删除包含主键值的行的操作&#xff0c;该值由其它表的现有行中的外键引用。在级联删除中&#xff0c;还删除其外键值引用删除的主键值的所有行。 级联更新是指更新主键值的操作&#xff0c;该值由其它表的现有行中的外键引用。在级联更新中&a…

正则表达式

正则表达式简介&#xff1a; 正则表达式是对字符串操作的一种逻辑公式&#xff0c;就是用事先定义好的一些特定字符、及这些特定字符的组合&#xff0c;组成一个“规则字符串”&#xff0c;这个“规则字符串”用来表达对字符串的一种过滤逻辑。   给定一个正则表达式和另一个…

SQL Server2005中触发器的运用

编写过存储过程的人&#xff0c;再编写触发器时会发现&#xff1a;他们的语法、格式是非常类似的。其实触发器就是一种特殊类型的存储过程。他们都是预编译的&#xff0c;在程序正式编译前就由编译器进行编译&#xff0c;存储在服务器端。 不过&#xff0c;触发器与一般的存储过…

关于SimpleDateFormat安全的时间格式化线程安全问题

关于SimpleDateFormat安全的时间格式化线程安全问题 2014年02月18日 16:19:40 zxh87 阅读数&#xff1a;34426 想必大家对SimpleDateFormat并不陌生。SimpleDateFormat 是 Java 中一个非常常用的类&#xff0c;该类用来对日期字符串进行解析和格式化输出&#xff0c;但如果使用…

LaTex - 插入公式 (从MathType公式编辑器导入到LaTex中)

原创 LaTex 论文排版(2): 插入公式 (从MathType公式编辑器导入到LaTex中) 2019年03月08日 09:37:40 在水一方xym 阅读数 5948 更多 分类专栏&#xff1a; LaTex 论文排版 LaTex 论文排版 版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&…

CSS总结

自从做牛腩新闻发布系统的时候&#xff0c;就开始了CSS的学习。CSS这部分知识并不是孤立的&#xff0c;它与JavaScript&#xff0c;与XML&#xff0c;与AJAX等都有着密切的关系。在制作网页的过程中&#xff0c;CSS就是充当一个化妆师的角色&#xff0c;它能够让我们制作出各式…

大型网站应用之海量数据和高并发解决方案总结

一、网站应用背景 开发一个网站的应用程序&#xff0c;当用户规模比较小的时候&#xff0c;使用简单的&#xff1a;一台应用服务器一台数据库服务器一台文件服务器&#xff0c;这样的话完全可以解决一部分问题&#xff0c;也可以通过堆硬件的方式来提高网站应用的访问性能&…

ehcache memcache redis三大缓存男高音

&#xfeff;&#xfeff; 研究使用缓存已经有一段时间了&#xff0c;今天本来想对比一下它们异同以及使用场景。然后我发现已经有前辈做了很不错的总结&#xff0c;而且这篇文章跟我也有很多共鸣。我想说的也就这些&#xff0c;所以这里就直接拿来主义了。 不过&#xff0c;还…

技术是个王八蛋,可是长得真好看

看完题目&#xff0c;请勿喷。最近的生活可能太苦逼了&#xff0c;好想吐槽一下~~~ 首先&#xff0c;先来分享一段个人特别喜欢的话&#xff1a; 透视社会依次为三个层面&#xff1a;制度、文化和技术。小到一个人&#xff0c;大到一个国家&#xff0c;一个民族&#xff0c;任…

学习,不是一件发愁的事儿

曾经&#xff0c;我有一个很幼稚的想法。有人告诉我&#xff1a;人体的细胞&#xff0c;每隔七年&#xff0c;就会大换血一次&#xff0c;经历一个大的生命周期。听完我就害怕了&#xff0c;七年&#xff1f;那七年后&#xff0c;我现在学习的所有知识&#xff0c;就全被我忘干…

记一次通过Memory Analyzer分析内存泄漏的解决过程

状况描述&#xff1a; 最近项目新打的版本&#xff0c;过不了多长时间&#xff0c;项目就会挂掉。状况就是处于一种假死的状态。索引查询都很慢&#xff0c;几乎进行不了任何操作&#xff0c;慢慢卡死。 然后我们再发版时&#xff0c;只能基于之前打好的war包&#xff0c;替换或…

数字图像处理之尺度空间理论

尺度空间(scale space)思想最早是由Iijima于1962年提出的&#xff0c;后经witkin和Koenderink等人的推广逐渐得到关注&#xff0c;在计算机视觉领域使用广泛。 尺度空间理论的基本思想是&#xff1a;在图像信息处理模型中引入一个被视为尺度的参数&#xff0c;通过连续变化尺度…

为什么要用高斯核来生成尺度空间?

信号的尺度空间刚提出是就是通过一系列单参数、宽度递增的高斯滤波器将原始信号滤波得到到组低频信号。那么有一个疑问就是&#xff0c;除了高斯滤波之外&#xff0c;其他带有参数t的低通滤波器是否也可以用来生成一个尺度空间呢&#xff1f; 但翻看资料得知国外诸多学者都已经…

【高分论文密码】大尺度空间模拟预测与数字制图教程

详情点击链接&#xff1a;【高分论文密码】大尺度空间模拟预测与数字制图 一&#xff0c;R语言空间数据及数据挖掘关键技术 1、R语言空间数据及应用特点 1)R语言基础与数据科学 2)R空间矢量数据 3)R栅格数据 2、R语言空间数据挖掘关键技术 二&#xff0c;R语言空间数据高…

尺度空间及SIFT

尺度空间方法的基本思想是&#xff1a;在视觉信息处理模型中引入一个被视为尺度的参数&#xff0c;通过连续变化尺度参数获得不同尺度下的视觉处理信息&#xff0c;然后综合这些信息以深入地挖掘图像的本质特征。尺度空间方法将传统的单尺度视觉信息处理技术纳入尺度不断变化的…

【高分论文密码】大尺度空间模拟预测与数字制图

大尺度空间模拟预测和数字制图技术和不确定性分析广泛应用于高分SCI论文之中&#xff0c;号称高分论文密码。大尺度模拟技术可以从不同时空尺度阐明农业生态环境领域的内在机理和时空变化规律&#xff0c;又可以为复杂的机理过程模型大尺度模拟提供技术基础。在本次培训中&…

尺度空间理论与图像金字塔(二)

SIFT简介 整理一下方便阅读&#xff0c;作者写的东西摘自论文&#xff0c;在此感谢xiaowei等的贡献 DoG尺度空间构造&#xff08;Scale-space extrema detection&#xff09;http://blog.csdn.net/xiaowei_cqu/article/details/8067881关键点搜索与定位&#xff08;Keypoint l…

遥感空间尺度转换技术(升尺度和降尺度)

遥感图像的一个基本特征是空间分辨率。目前已经可以有效获取大量不同空间分辨率遥感数据。 尺度和尺度转换已经成为遥感的核心问题之一,人们已经从不同角度提出了这一问题。尺度转换分为两种: 升尺度:从高分辨率到低分辨率的转换;降尺度:从低分辨率到高分辨率的转换。文章…