Swing的学习教程链接:Java Swing教程:30分钟玩转Swing界面设计。
图片处理的参考文章:https://blog.csdn.net/qq_36511401/category_9467762.html
一、介绍
1、Swing。
Swing是一个用于开发Java应用程序用户界面的开发工具包。以抽象窗口工具包(AWT)为基础使跨平台应用程序可以使用任何可插拔的外观风格。Swing开发人员只用很少的代码就可以利用Swing丰富、灵活的功能和模块化组件来创建优雅的用户界面。工具包中所有的包都是以swing作为名称,例如javax.swing,javax.swing.event。
2、Awt。
AWT(Abstract Window Toolkit),中文译为抽象窗口工具包,该包提供了一套与本地图形界面进行交互的接口,是Java提供的用来建立和设置Java的图形用户界面的基本工具。AWT中的图形函数与操作系统所提供的图形函数之间有着一一对应的关系,称之为peers,当利用AWT编写图形用户界面时,实际上是在利用本地操作系统所提供的图形库。由于不同 操作系统的图形库所提供的样式和功能是不一样的,在一个平台上存在的功能在另一个平台上则可能不存在。为了实现Java语言所宣称的“一次编写,到处运行(write once, run anywhere)”的概念,AWT不得不通过牺牲功能来实现平台无关性,也即AWT所提供的图形功能是各种操作系统所提供的图形功能的交集。
3、区别。
在实际应用中,应该使用AWT还是Swing取决于应用程序所部署的平台类型。对于一个嵌入式应用,目标平台的硬件资源往往非常有限,而应用程序的运行速度又是项目中至关重要的因素。在这种矛盾的情况下,简单而高效的AWT当然成了嵌入式Java的第一选择。在普通的基于PC或者是工作站的标准Java应用中,硬件资源对应用程序所造成的限制往往不是项目中的关键因素。所以在标准版的Java中则提倡使用Swing, 也就是通过牺牲速度来实现应用程序的功能。
二、代码
1、主流程。
package com.zxj.reptile.test.image.view;
import com.zxj.reptile.utils.image.view.ImageViewUtils;
import javax.swing.*;
import java.awt.*;
public class ImageTool {
/**
* 程序入口
*/
public static void main(String[] args) {
final int frameHeight = 200;
final int frameWidth = 800;
//JPanel面板
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new GridLayout(2, 1, 1, 1));//网格布局
JFrame frame = new JFrame("图像处理小工具");
openImagePixel(frame, centerPanel);//查看图片像素
JPanel panel = new JPanel();
ImageViewUtils.rootPanelInit(panel, frameWidth, frameHeight);
panel.add(centerPanel, BorderLayout.CENTER);
//JFrame窗口
ImageViewUtils.frameInit(frame, panel, frameWidth, frameHeight);
}
/**
* 展示图片或者图片像素值(分为原始的、rgb的、灰度化的、二值化的)
*/
private static void openImagePixel(JFrame frame, JComponent parentView) {
JButton label = new JButton();
JTextField textField = new JTextField();
JPanel panel_1 = new JPanel();
ImageViewUtils.setMargin(panel_1, 20, 10, 10, 20);
panel_1.setLayout(new FlowLayout(FlowLayout.LEFT));//流式布局(默认),左对齐
panel_1.add(label);
panel_1.add(textField);
JButton btnShow = new JButton();
JButton btnRgb = new JButton();
JButton btnGray = new JButton();
JButton btnBinary = new JButton();
JButton btnHistogram = new JButton();
JPanel panel_2 = new JPanel();
ImageViewUtils.setMargin(panel_2, 20, 10, 10, 20);
panel_2.setLayout(new FlowLayout(FlowLayout.LEFT));//流式布局(默认),左对齐
panel_2.add(btnShow);
panel_2.add(btnRgb);
panel_2.add(btnGray);
panel_2.add(btnBinary);
panel_2.add(btnHistogram);
parentView.add(panel_1);
parentView.add(panel_2);
label.setText("选择文件:");
label.addActionListener(e -> {
FileDialog openFileDialog = new FileDialog(frame, "选择文件");
openFileDialog.setMode(FileDialog.LOAD); //设置此对话框为从文件加载内容
openFileDialog.setFile("*.jpg;*.jpeg;*.gif;*.png;*.bmp;*.tif;");
openFileDialog.setVisible(true);
String fileName = openFileDialog.getFile();
String directory = openFileDialog.getDirectory();
if (null != fileName) {
textField.setText(directory + fileName);
} else {
JOptionPane.showMessageDialog(frame, "您已经取消选择了,请重新选择!");
}
});
//
textField.setColumns(45);
//
btnShow.setText("查看图片");
btnShow.addActionListener(e -> {
ImageViewUtils.showImage(textField.getText());
});
//
btnRgb.setText("RGB值");
btnRgb.addActionListener(e -> {
ImageViewUtils.getRgbPixel(textField.getText());
});
//
btnGray.setText("灰度值");
btnGray.addActionListener(e -> {
ImageViewUtils.getGrayPixel(textField.getText());
});
//
btnBinary.setText("二值化值");
btnBinary.addActionListener(e -> {
ImageViewUtils.getBinaryPixel(textField.getText());
});
//
btnHistogram.setText("灰度直方图");
btnHistogram.addActionListener(e -> {
ImageViewUtils.showHistogram(textField.getText());
});
}
}
2、ImageViewUtils.java。
package com.zxj.reptile.utils.image.view;
import com.zxj.reptile.utils.image.ImageUtils;
import com.zxj.reptile.utils.number.StringUtils;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Timer;
import java.util.TimerTask;
public class ImageViewUtils {
/**
* 展示图片像素值--rgb的
*/
public static void getRgbPixel(String sourcePath) {
try {
BufferedImage image = ImageIO.read(new File(sourcePath));
int[][] imgArrays = ImageUtils.getImageRgb(image);
getPixel(imgArrays, sourcePath.split("\\.")[1]);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 展示图片像素值--灰度化的
*/
public static void getGrayPixel(String sourcePath) {
try {
BufferedImage image = ImageIO.read(new File(sourcePath));
int[][] imgArrays = ImageUtils.getImageGray(image);
getPixel(imgArrays, sourcePath.split("\\.")[1]);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 展示图片像素值--二值化的
*/
public static void getBinaryPixel(String sourcePath) {
try {
BufferedImage image = ImageIO.read(new File(sourcePath));
int[][] imgArrays = ImageUtils.getImageBinary(image);
getPixel(imgArrays, StringUtils.getFileName(sourcePath));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 展示图片像素值(分为原始的、rgb的、灰度化的、二值化的)
*
* @param array 元素的像素值
* @param title Iframe窗口标题
*/
private static void getPixel(int[][] array, String title) {
final int frameHeight = 800;
final int frameWidth = 1000;
//数据处理
int row = array.length;
int column = array[0].length + 1;
Object[] firstRow = new Object[column];//列数
firstRow[0] = "列数/行数";
for (int i = 1; i < column; i++) {
firstRow[i] = i;
}
Object[][] contentRow = new Object[row][column];//行数
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
if (j == 0) {
contentRow[i][0] = i + 1;
} else {
contentRow[i][j] = array[i][j - 1];
}
}
}
//JTable表格
JTable table = new JTable(contentRow, firstRow);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
//每列的宽度为:当前列最长内容单元格的宽度
for (int i = 0; i < table.getColumnCount(); i++) {
int maxWidth = 0;
for (int j = 0; j < table.getRowCount(); j++) {
TableCellRenderer rend = table.getCellRenderer(j, i);
Object value = table.getValueAt(j, i);
Component comp = rend.getTableCellRendererComponent(table, value, false, false, j, i);
maxWidth = Math.max(comp.getPreferredSize().width, maxWidth);
}
table.getColumnModel().getColumn(i).setPreferredWidth((int) (maxWidth + maxWidth * 0.05));
}
//JScrollPane面板
JScrollPane scrollPane = new JScrollPane(table,
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);//JScrollPane
//JFrame窗口
JFrame frame = new JFrame(title);
frameInit(frame, scrollPane, frameWidth, frameHeight);
}
//-----------------------------------------------------------------//
/**
* 查看图片
*
* @param sourcePath 图片地址
*/
public static void showImage(String sourcePath) {
try {
//JLabel
JLabel label = new JLabel();
label.setIcon(new ImageIcon(sourcePath));
//JPanel面板
JPanel panel = new JPanel();
panel.add(label);
//JFrame窗口
JFrame frame = new JFrame("图片查看:" + StringUtils.getFileName(sourcePath));
frame.setContentPane(panel);
frame.setSize(200, 200);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);//只会关闭当前窗口
frame.setLocationRelativeTo(null);//居中
frame.pack();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 查看灰度直方图
*/
public static void showHistogram(String sourcePath) {
final int histogramFrameWidth = 500;
final int histogramFrameHeight = 500;
final int histogramWidth = 400;
final int histogramHeight = 400;
final int histogramMargin = 20;
try {
Canvas histCanvas = new Canvas();
histCanvas.setSize(histogramWidth, histogramHeight);
//JPanel面板
JPanel histogramPanel = new JPanel();
histogramPanel.setSize(histogramWidth, histogramHeight);
histogramPanel.setPreferredSize(new Dimension(histogramWidth, histogramHeight));
histogramPanel.setBorder(new LineBorder(Color.blue));
histogramPanel.add(histCanvas);
JPanel panel = new JPanel();
ImageViewUtils.rootPanelInit(panel, histogramFrameWidth, histogramFrameHeight);
panel.add(histogramPanel, BorderLayout.CENTER);
//JFrame窗口
JFrame frame = new JFrame("title");
ImageViewUtils.frameInit(frame, panel, histogramFrameWidth, histogramFrameHeight);
new Timer().schedule(new TimerTask() {
@Override
public void run() {
try {
BufferedImage image = ImageIO.read(new File(sourcePath));
int[][] imgArrays = ImageUtils.getImageGray(image);
int[] statisticArray = ImageUtils.statisticGray(imgArrays);
int max = 0;
for (int value : statisticArray) {
if (max < value) {
max = value;
}
}
double multiply = (histogramHeight * 0.8) / max;
for (int i = 0; i < statisticArray.length; i++) {
statisticArray[i] = (int) Math.round(statisticArray[i] * multiply);
}
Graphics g = histCanvas.getGraphics();
Color c = g.getColor();
g.setColor(Color.red);
g.drawLine(histogramMargin, histogramHeight - histogramMargin, histogramWidth - histogramMargin, histogramHeight - histogramMargin);
g.drawLine(histogramWidth - histogramMargin, histogramHeight - histogramMargin, histogramWidth - histogramMargin * 2, (int) (histogramHeight - histogramMargin * 0.66));
g.drawLine(histogramWidth - histogramMargin, histogramHeight - histogramMargin, histogramWidth - histogramMargin * 2, (int) (histogramHeight - histogramMargin * 1.33));
g.drawString("灰度级", histogramWidth - 80, histogramHeight - 5);
g.drawLine(histogramMargin, histogramHeight - histogramMargin, histogramMargin, histogramMargin);
g.drawLine(histogramMargin, histogramMargin, (int) (histogramMargin * 0.66), histogramMargin * 2);
g.drawLine(histogramMargin, histogramMargin, (int) (histogramMargin * 1.33), histogramMargin * 2);
g.drawString("像素个数", 0, 20);
g.setColor(Color.black);
for (int i = 0; i < statisticArray.length; i++) {
g.drawLine(histogramMargin + i, histogramHeight - histogramMargin, histogramMargin + i, histogramHeight - histogramMargin - statisticArray[i]);
if (i % 30 == 0) {
g.drawString(i + "", histogramMargin + i, histogramHeight - 5);
}
}
g.setColor(c);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}, 500);
} catch (Exception e) {
e.printStackTrace();
}
}
//-----------------------------------------------------------------//
/**
* 设置指定控件的边距,本质上是设置控件的不可见边框
*
* @param component 控件
* @param top 上边距
* @param bottom 下边距
* @param left 左边距
* @param right 右边距
*/
public static void setMargin(JComponent component, int top, int bottom, int left, int right) {
Border border = BorderFactory.createEmptyBorder(top, left, bottom, right);
component.setBorder(border);
}
/**
* 初始化frame
*/
public static void frameInit(JFrame frame, JComponent panel, int width, int height) {
frame.setContentPane(panel);
frame.setSize(width, height);//没有这个会不居中
frame.setPreferredSize(new Dimension(width, height));//没有这个大小不会变
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);//只会关闭当前窗口
frame.setLocationRelativeTo(null);//居中
frame.pack();
frame.setVisible(true);
}
/**
* 初始化panel
*/
public static void rootPanelInit(JPanel panel, int width, int height) {
panel.setSize(width, height);
panel.setPreferredSize(new Dimension(width, height));
panel.setBorder(new EmptyBorder(new Insets(10, 10, 10, 10)));
panel.setLayout(new BorderLayout());
}
}
3、ImageUtils.java。
package com.zxj.reptile.utils.image;
import java.awt.image.BufferedImage;
/**
* 要用int,不能使用byte,因为byte最大值为128
*/
public class ImageUtils {
/**
* 灰度处理的方法
*/
public static final byte Gray_Type_Min = 1;//最大值法
public static final byte Gray_Type_Max = 2;//最小值法
public static final byte Gray_Type_Average = 3;//平均值法
public static final byte Gray_Type_Weight = 4;//加权法
public static final byte Gray_Type_Red = 5;//红色值法
public static final byte Gray_Type_Green = 6;//绿色值法
public static final byte Gray_Type_Blue = 7;//蓝色值法
public static final byte Gray_Type_Default = Gray_Type_Weight;//默认加权法
/**
* 不同颜色通道的图片
*/
public static final byte Channel_Color_Red = 1;
public static final byte Channel_Color_Green = 2;
public static final byte Channel_Color_Blue = 3;
//-----------------------------------------------------------------//
/**
* 灰度化处理,彩色int[][] 转 灰度byte[][]
*
* @param imgArrays 图像二维数组
* @param grayType 灰度化方法
*/
public static int[][] grayProcess(int[][] imgArrays, int grayType) throws Exception {
int[][] newImgArrays = new int[imgArrays.length][imgArrays[0].length];
for (int h = 0; h < imgArrays.length; h++)
for (int w = 0; w < imgArrays[0].length; w++)
newImgArrays[h][w] = getImageGray(getImageRgb(imgArrays[h][w]), grayType);
return newImgArrays;
}
/**
* 颜色通道处理,彩色int[][] 转 彩色int[][]
*
* @param imgArrays 图像二维数组
* @param channelColor 不同颜色通道
*/
public static int[][] channelProcess(int[][] imgArrays, int channelColor) {
int[][] newImgArrays = new int[imgArrays.length][imgArrays[0].length];
for (int h = 0; h < imgArrays.length; h++) {
for (int w = 0; w < imgArrays[0].length; w++) {
final int pixel = imgArrays[h][w];
if (channelColor == Channel_Color_Red) {
newImgArrays[h][w] = pixel & 0xff0000;
} else if (channelColor == Channel_Color_Green) {
newImgArrays[h][w] = pixel & 0x00ff00;
} else if (channelColor == Channel_Color_Blue) {
newImgArrays[h][w] = pixel & 0x0000ff;
}
}
}
return newImgArrays;
}
/**
* 二值化处理,灰度byte[][] 转 二值byte[][]
*
* @param imgArrays 灰度 int[][]
* @param threshold 阈值
*/
public static int[][] binaryProcess(int[][] imgArrays, int threshold) {
int[][] newImgArrays = new int[imgArrays.length][imgArrays[0].length];
for (int h = 0; h < imgArrays.length; h++)
for (int w = 0; w < imgArrays[0].length; w++) {
newImgArrays[h][w] = (imgArrays[h][w] < threshold ? 0 : 0xff);
}
return newImgArrays;
}
//-----------------------------------------------------------------//
/**
* 根据像素,返回r、g、b 的 byte[]
*
* @param pixel 像素值
*/
private static int[] getImageRgb(int pixel) {
int[] rgb = new int[3];
rgb[0] = ((pixel >> 16) & 0xff);
rgb[1] = ((pixel >> 8) & 0xff);
rgb[2] = (pixel & 0xff);
return rgb;
}
/**
* 获取像素值
*
* @param pixel 像素值
*/
public static long getPixel(int pixel) {
return (pixel & 0xff) + (pixel & 0xff00) + (pixel & 0xff0000);
}
/**
* 获取像素值
*
* @param rgb r、g、b 的 byte[]
*/
public static long getPixel(int[] rgb) {
return (rgb[0] << 16) + (rgb[1] << 8) + rgb[2];
}
/**
* 根据r、g、b 的 byte[],返回灰度值
*
* @param rgb r、g、b颜色通道的值
* @param grayType 不同灰度处理的方法
*/
private static int getImageGray(int[] rgb, int grayType) throws Exception {
if (grayType == Gray_Type_Average) {
return ((rgb[0] + rgb[1] + rgb[2]) / 3); //rgb之和除以3
} else if (grayType == Gray_Type_Weight) {
return (int) (0.3 * rgb[0] + 0.59 * rgb[1] + 0.11 * rgb[2]);
} else if (grayType == Gray_Type_Red) {
return rgb[0];//取红色值
} else if (grayType == Gray_Type_Green) {
return rgb[1];//取绿色值
} else if (grayType == Gray_Type_Blue) {
return rgb[2];//取蓝色值
}
//比较三个数的大小
int gray = rgb[0];
for (int i = 1; i < rgb.length; i++) {
if (grayType == Gray_Type_Min) {
if (gray > rgb[i]) {
gray = rgb[i];//取最小值
}
} else if (grayType == Gray_Type_Max) {
if (gray < rgb[i]) {
gray = rgb[i];//取最大值
}
} else {
throw new Exception("grayType出错");
}
}
return gray;
}
//-----------------------------------------------------------------//
/**
* 获取图像像素 byte[][] rgb值
*
* @param image BufferedImage图像对象
*/
public static int[][] getImageRgb(BufferedImage image) {
int[][] imgArrays = new int[image.getHeight()][image.getWidth()];
for (int i = 0; i < image.getHeight(); i++)
for (int j = 0; j < image.getWidth(); j++)
imgArrays[i][j] = image.getRGB(j, i);
return imgArrays;
}
/**
* 获取图像像素 byte[][] 灰度值
*
* @param image BufferedImage图像对象
*/
public static int[][] getImageGray(BufferedImage image) throws Exception {
return grayProcess(getImageRgb(image), Gray_Type_Default);
}
/**
* 获取图像像素 byte[][] 二值
*
* @param image BufferedImage图像对象
*/
public static int[][] getImageBinary(BufferedImage image) throws Exception {
return binaryProcess(grayProcess(getImageRgb(image), Gray_Type_Default), 0xff / 2);
}
/**
* 图像像素填充 byte[][]
*
* @param image BufferedImage图像对象
* @param imgArrays 二维像素
*/
public static void setImageBytes(BufferedImage image, int[][] imgArrays) {
for (int i = 0; i < image.getHeight(); i++)
for (int j = 0; j < image.getWidth(); j++)
image.setRGB(j, i, (byte) imgArrays[i][j]);
}
/**
* 图像像素填充 byte[][]
*
* @param image BufferedImage图像对象
* @param imgArrays 二维像素
*/
public static void setImageBytes(BufferedImage image, byte[][] imgArrays) {
for (int i = 0; i < image.getHeight(); i++)
for (int j = 0; j < image.getWidth(); j++)
image.setRGB(j, i, imgArrays[i][j]);
}
/**
* 图像像素填充 int[][]
*
* @param image BufferedImage图像对象
* @param imgArrays 二维像素
*/
public static void setImageRgb(BufferedImage image, int[][] imgArrays) {
for (int i = 0; i < image.getHeight(); i++)
for (int j = 0; j < image.getWidth(); j++)
image.setRGB(j, i, imgArrays[i][j]);
}
/**
* 图像像素填充 将 byte[][] 变为 int[][] 进行填充
*
* @param image BufferedImage图像对象
* @param imgArrays 二维像素
*/
public static void setImageRgbByByte(BufferedImage image, int[][] imgArrays) {
for (int i = 0; i < image.getHeight(); i++)
for (int j = 0; j < image.getWidth(); j++)
image.setRGB(j, i, imgArrays[i][j] + (imgArrays[i][j] << 8) + (imgArrays[i][j] << 16));
}
//-----------------------------------------------------------------//
/**
* 将数组的值域分布到0--0xff之间
*/
public static int[][] rangeToByte(int[][] arrays) {
int max = arrays[0][0], min = arrays[0][0];
for (int[] array : arrays) {
for (int value : array) {
if (value > max) {
max = value;
} else if (value < min) {
min = value;
}
}
}
//
int[][] newArrays = new int[arrays.length][];
int range = max - min + 1;
double multiply = (0xff + 1.0) / range;
for (int i = 0; i < arrays.length; i++) {
int[] array = arrays[i];
int[] newArray = new int[array.length];
for (int j = 0; j < array.length; j++) {
int value = (int) Math.round((array[j] - min) * multiply);
newArray[j] = value > 0xff ? 0xff : value;
}
newArrays[i] = newArray;
}
return newArrays;
}
/**
* 统计灰度分布,0-->255
*/
public static int[] statisticGray(int[][] arrays) {
int[] statisticArray = new int[0xff + 1];
int row = arrays.length;
int column = arrays[0].length;
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
statisticArray[arrays[i][j]]++;
}
}
return statisticArray;
}
}
4、StringUtils.java。
package com.zxj.reptile.utils.number;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class StringUtils {
public static boolean isBlank(String str) {
return str == null || str.isEmpty();
}
public static boolean isNotBlank(String str) {
return !isBlank(str);
}
/**
* @param str 要被逗号(不区分中英文)切割的字符串
* @return 字符串数组
*/
public static List<String> commaSplit(String str) {
List<String> list = new ArrayList<>();
if (isBlank(str)) {
return list;
}
str = str.replace(",", ",");
str = str.replace(" ", "");
String[] strArray = str.split(",");
for (String item : strArray) {
if (isNotBlank(item)) {
list.add(item);
}
}
return list;
}
/**
* 获取文件路径中的文件名
*
* @param filePath 文件路径
*/
public static String getFileName(String filePath) {
String[] strArray = filePath.split(File.separator.equals("\\") ? "\\\\" : File.separator);
return strArray[strArray.length - 1];
}
}
三、结果
1、主界面。
2、选择图片。
3、查看图片。
4、查看图片的RGB值。
5、查看图片的灰度值。
6、查看图片的二值化值。
7、查看图片的灰度直方图。