需求:
在浏览器中给用户呈现一张图片,用户点击图片中的某些标志物,需要系统给出标志物的信息反馈,达到一个交互的作用。
比如下图中,点击某个封闭区域时候,需要告知用户点击的区域名称及图形形状特性等等。
实现思路模仿 window系统中画图工具的区域填充工具。
当我们给一个封闭区域填充色彩的时候,整个区域都将得到填充相同的颜色,此区域封闭即可,这样我们将一张图片中的不同区域填充不同的色彩,得到如下的图片:
后续只需要通过xy坐标得到颜色,在通过颜色得到对应的图片相关信息即可。应用时候的复杂度为O(1)
实现代码如下:
java
import javax.imageio.ImageIO;
import static org.assertj.core.api.Assertions.useDefaultDateFormatsOnly;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ImageRGBMatrix {
//边界的颜色
static final int flagColor = 237;
//需要填充的色彩
static int setColor = 20+(0xFF << 8);
public static void main(String[] args) {
try {
// 读取图片
BufferedImage image = ImageIO.read(new File("C:\\Users\\hxd\\Desktop\\pdy.png"));
int width = image.getWidth();
int height = image.getHeight();
初始化特征矩阵//
int[][] characteristicMatrix = new int[width][height];
// 遍历图片的每个像素
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
// 获取(x, y)位置的像素
int pixel = image.getRGB(x, y);
// 获取RGB分量
short red = (short) ((pixel >> 16) & 0xFF);
// short green = (short) ((pixel >> 8) & 0xFF);
// short blue = (short) (pixel & 0xFF);
characteristicMatrix[x][y] = red;
}
}
///初始化特征矩阵完成/
///基于点进行矩阵区域填充/
List<Point> ps = new ArrayList<>();
ps.add(new Point(116,140,"1","A",0));
ps.add(new Point(427,116,"2","B",0));
ps.add(new Point(203,426,"3","C",0));
ps.add(new Point(661,382,"4","D",0));
ps.add(new Point(543,609,"5","E",0));
Map<Integer,Point> color2Points = new HashMap<>();
for (Point p : ps) {
int my = p.getY();
int mx = p.getX();
setColor += 40;
p.setColor(setColor);
color2Points.put(setColor, p);
//初始上
for (int y = my; y > -1 && characteristicMatrix[mx][y] !=flagColor; y--) {
characteristicMatrix[mx][y] = setColor;
}
//初始下
for (int y = my+1; y < height && characteristicMatrix[mx][y] !=flagColor; y++) {
characteristicMatrix[mx][y] = setColor;
}
//记录是否有新增加的点
boolean isAdd = true;
while(isAdd) {
//一旦没有扩充新鲜点,则退出
//横向扩充
isAdd = leftRigthScan(width, height, characteristicMatrix);
if(isAdd) {
//轴向扩充
isAdd = upDownScan(width, height, characteristicMatrix);
}
}
}
///基于点进行矩阵区域填充完成/
///开始实在使用,找到具体的点在哪个区域/
List<Point> pp = new ArrayList<>();
pp.add(new Point(116,140));
pp.add(new Point(116,145));
pp.add(new Point(596,358));
for (Point p : pp) {
int color = characteristicMatrix[p.getX()][p.getY()];
System.out.println(color2Points.get(color));
}
///开始实在使用,找到具体的点在哪个区域完成/
///可视化输出,仅仅是让给人看看填充是否正确,对实际使用没有作用/
BufferedImage image1 = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image1.setRGB(x,y,characteristicMatrix[x][y]);
}
}
ImageIO.write(image1, "png", new File("d:\\pdypdypdy.png"));
///可视化输出,仅仅是让给人看看填充是否正确,对实际使用没有作用/
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 纵向扫描
* 从左到右一列一列的扫描:
* 从上到下扫描y列: (y在变化)
* 1、如果是非着色的点,则继续下移。如果是着色点,执行2、3两步骤。如果超出数组边界则开始下一列
* 2、基于此着色点向上侧扩张,直到上侧点是边界点或者下标超出数组下界0;
* 3、基于此着色点向下侧扩张,直到下侧点是边界点或者下标超出数组上界height;更新扫描点为当前最下侧扩张点 继续第1步执行。;
*
*
* @param width
* @param height
* @param characteristicMatrix
* @return
*/
private static boolean upDownScan(int width, int height, int[][] characteristicMatrix) {
boolean isAdd = false;
//看横向的线
for (int x = 0; x < width; x++) {
int y = 0;
while(y < height) {
for (; y < height; y++) {
if(characteristicMatrix[x][y] == setColor) {
break ;
}
}
if(y < height) {
//此列有
//处理上边
for (int uy = y-1; uy > -1 && characteristicMatrix[x][uy] !=flagColor; uy--) {
if(characteristicMatrix[x][uy] != setColor) {
characteristicMatrix[x][uy] = setColor;
isAdd = true;
}
}
//处理下边
for (y = y+1; y < height && characteristicMatrix[x][y] !=flagColor; y++) {
if(characteristicMatrix[x][y] != setColor) {
characteristicMatrix[x][y] = setColor;
isAdd = true;
}
}
}
}
}
return isAdd;
}
//左右横向扫描
/**
* 左右横向扫描
* 从上到下一行一行的开始扫描扩张。
* 从左到右扫描x行:
* 1、如果是非着色的点,则继续右移。如果是角色点,执行2、3两步骤。如果超出数组边界则开始下一行
* 2、基于此着色点向左侧扩张,直到左侧点是边界点或者下标超出数组下界0;
* 3、基于此着色点向右侧扩张,直到右侧点是边界点或者下标超出数组上界width;更新扫描点为当前最右侧扩张点 继续第1步执行。;
*
* @param width
* @param height
* @param characteristicMatrix
* @return
*/
protected static boolean leftRigthScan(int width, int height, int[][] characteristicMatrix) {
boolean isAdd = false;
for (int y = 0; y < height; y++) {
int x = 0;
while(x < width) {
for (; x < width; x++) {
if(characteristicMatrix[x][y] == setColor) {
break ;
}
}
if(x < width) {
//此行有
//处理左边
for (int lx = x-1; lx > -1 && characteristicMatrix[lx][y] !=flagColor; lx--) {
if(characteristicMatrix[lx][y] != setColor) {
characteristicMatrix[lx][y] = setColor;
isAdd = true;
}
}
//处理右边
for (x = x+1; x < width && characteristicMatrix[x][y] !=flagColor; x++) {
if(characteristicMatrix[x][y] != setColor) {
characteristicMatrix[x][y] = setColor;
isAdd = true;
}
}
}
}
}
return isAdd;
}
}