基于java实现图片中任意封闭区域识别

需求:

在浏览器中给用户呈现一张图片,用户点击图片中的某些标志物,需要系统给出标志物的信息反馈,达到一个交互的作用。

比如下图中,点击某个封闭区域时候,需要告知用户点击的区域名称及图形形状特性等等。

实现思路模仿 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;
	}
}
相关推荐
yngsqq21 分钟前
一键打断线(根据相交点打断)——CAD c# 二次开发
windows·microsoft·c#
V+zmm1013429 分钟前
基于微信小程序的乡村政务服务系统springboot+论文源码调试讲解
java·微信小程序·小程序·毕业设计·ssm
Oneforlove_twoforjob1 小时前
【Java基础面试题025】什么是Java的Integer缓存池?
java·开发语言·缓存
xmh-sxh-13141 小时前
常用的缓存技术都有哪些
java
AiFlutter1 小时前
Flutter-底部分享弹窗(showModalBottomSheet)
java·前端·flutter
咸鱼桨2 小时前
《庐山派从入门到...》PWM板载蜂鸣器
人工智能·windows·python·k230·庐山派
J不A秃V头A2 小时前
IntelliJ IDEA中设置激活的profile
java·intellij-idea
DARLING Zero two♡2 小时前
【优选算法】Pointer-Slice:双指针的算法切片(下)
java·数据结构·c++·算法·leetcode
小池先生2 小时前
springboot启动不了 因一个spring-boot-starter-web底下的tomcat-embed-core依赖丢失
java·spring boot·后端
CodeClimb2 小时前
【华为OD-E卷-木板 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od