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

news2024/7/4 6:00:04

需求:
在浏览器中给用户呈现一张图片,用户点击图片中的某些标志物,需要系统给出标志物的信息反馈,达到一个交互的作用。
比如下图中,点击某个封闭区域时候,需要告知用户点击的区域名称及图形形状特性等等。
原始图片
实现思路模仿 window系统中画图工具的区域填充工具。在这里插入图片描述
当我们给一个封闭区域填充色彩的时候,整个区域都将得到填充相同的颜色,此区域封闭即可,这样我们将一张图片中的不同区域填充不同的色彩,得到如下的图片:
在这里插入图片描述
后续只需要通过xy坐标得到颜色,在通过颜色得到对应的图片相关信息即可。应用时候的复杂度为O(1)

实现代码如下:

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;
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1715806.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Django之rest_framework(九)

一、分页-PageNumberPagination类 REST framework提供了分页的支持 官网:Pagination - Django REST framework 1.1、全局设置 # settings.py REST_FRAMEWORK = {DEFAULT_PAGINATION_CLASS: rest_framework.pagination.PageNumberPagination,PAGE_SIZE: 100 # 每页数目 }提示…

相对论表明速度越快时间越慢,为什么速度会影响时间?

在物理学的宏伟殿堂中&#xff0c;相对论以其深邃的洞察力&#xff0c;挑战了我们对时间和空间的传统认识。1905年&#xff0c;阿尔伯特爱因斯坦提出了狭义相对论&#xff0c;揭示了在所有惯性参照系中&#xff0c;光速是常数的惊人事实。 随后在1915年&#xff0c;他进一步发展…

ABAP 在增强中COMMIT

前言 呃&#xff0c;又是很磨人的需求&#xff0c;正常情况下是不允许在增强中COMMIT的&#xff0c;会影响源程序本身的逻辑&#xff0c;但是这个需求就得这么干… 就是在交货单增强里面要再调用一次交货单BAPI&#xff0c;通过SO的交货单自动创建STO的交货单&#xff0c;如果…

uniapp h5项目切换导航栏及动态渲染按钮颜色

1.效果图 2.html,动态渲染按钮样式---三元判断 <!-- 切换栏 --><view class"statusList"><block v-for"(item,index) in list" :key"index"><view class"swiper-tab-list" :class"current item.id?activ…

基于扩散模型的,开源世界模型DIAMOND

日内瓦大学、微软研究院和爱丁堡大学的研究人员联合开源了&#xff0c;基于扩散模型的世界模型—DIAMOND。 研究人员之所以选择扩散模型作为基础&#xff0c;是因为可以更好地捕捉视觉细节&#xff0c;同时具有建模复杂多模态分布的能力&#xff0c;以便在不同的环境下进行训练…

网络融合的力量:企业如何通过“一网多用”提升业务效率

随着企业业务的不断扩展&#xff0c;网络需求变得日益复杂。需要的是一种能够统一承载办公、生产、销售和运营等多业务需求的网络架构。这种“一网多用”的架构&#xff0c;不仅简化了网络部署和管理&#xff0c;还提升了效率并降低了成本。 “一网多用”架构的实际应用&#x…

[ C++ ] 深入理解模板( 初 阶 )

函数模板 函数模板格式 template <typename T1, typename T2,......,typename Tn> 返回值类型 函数名(参数列表){} 注意&#xff1a; typename是用来定义模板参数关键字&#xff0c;也可以使用class(切记&#xff1a;不能使用struct代替class) 函数模板的实例化 模板参数…

文件预览的实现

1.pdf预览 使用iframe 如果是预览本地文件&#xff0c;且是vue项目&#xff0c;pdf文件需要放在public文件夹下。 调试环境&#xff1a;vue、vant、js <template><div style"height: 100%;width: 100%"><iframe :src"pageUrl" style&quo…

Docker容器测试-常见问题+解决

前言 问题1&#xff1a;创建 nginx 容器尝试挂载 nginx.conf 文件时报错&#xff1a; mounting “/root/nginx.conf” to rootfs at “/etc/nginx/nginx.conf” caused: mount through procfd: not a directory: 在自己的服务器上想通过 nginx 镜像创建容器&#xff0c;并挂载…

ROS | C++和python实现发布结点和订阅结点

发布者结点&#xff1a; 代码实现&#xff1a; python: C: C和Python发布结点的差异&#xff1a; python: 发布结点pub 大管家rospy调用publisher函数发布话题 (话题,类型&#xff0c;话题长度&#xff09; C: 先定义一个大管家&#xff1a;NodeHandle 然后大管家发布话题…

【leetcode——栈的题目】——1003. 检查替换后的词是否有效python

题目&#xff1a; 给你一个字符串 s &#xff0c;请你判断它是否 有效 。 字符串 s 有效 需要满足&#xff1a;假设开始有一个空字符串 t "" &#xff0c;你可以执行 任意次 下述操作将 t 转换为 s &#xff1a; 将字符串 "abc" 插入到 t 中的任意位置…

Dinky MySQLCDC 整库同步到 MySQL jar包冲突问题解决

资源&#xff1a;flink 1.17.0、dinky 1.0.2 问题&#xff1a;对于kafka相关的包内类找不到的情况 解决&#xff1a;使用 flink-sql-connector- 胖包即可&#xff0c;去掉 flink-connector- 相关瘦包&#xff0c;解决胖瘦包冲突 source使用 flink-sql-connector- 胖包&#…

2024年西安交通大学程序设计校赛

A题 签到题 代码如下 //A #include<iostream> #include<algorithm> #define int long long #define endl \n #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); using namespace std; signed main() {IOSint a,b,c,d;cin>>a>>b>>c…

景源畅信:抖音小店如何开橱窗?

在当今数字化时代&#xff0c;社交媒体平台不仅仅是人们交流和分享生活的工具&#xff0c;更成为了商家们展示和销售产品的重要场所。抖音作为一款流行的短视频社交应用&#xff0c;其内置的电商功能——抖音小店&#xff0c;为众多商家和个人提供了便捷的在线销售途径。其中&a…

geotrust通配符证书600元且赠送一个月

GeoTrust作为国际知名的数字证书颁发机构&#xff0c;旗下有RapidSSL、QuickSSL等子品牌经营着各种类型的SSL数字证书&#xff0c;其中RapidSSL旗下的SSL数字证书都是入门级的&#xff0c;性价比高。审核速度也比较快&#xff0c;证书的适用范围也比较广泛。今天就随SSL盾小编了…

一款开箱即用的Markdown 编辑器!【送源码】

开源的 Markdown 编辑器 Cherry Markdown Editor 是一款前端-markdown-编辑器-组件&#xff0c;具有开箱即用、轻量简洁、易于扩展等特点&#xff0c;它可以运行在浏览器或服务端 (NodeJs). 当 Cherry Markdown 编辑器支持的语法不满足开发者需求时&#xff0c;可以快速的进行…

在WHM中如何调整max_upload_size 参数大小

今日我们在搭建新网站时需要调整一下PHP参数max_upload_size 的大小&#xff0c;我们公司使用的Hostease的美国独立服务器产品默认5个IP地址&#xff0c;也购买了cPanel面板&#xff0c;因此联系Hostease的技术支持&#xff0c;寻求帮助了解到如何在WHM中调整PHP参数&#xff0…

蓝桥杯物联网竞赛_STM32L071KBU6_对于EEPROM的新理解

EEPROM写函数&#xff1a; void Function_GetEepromData(){Function_EepromRead(4, BUFF);OLED_ShowChar(0, 0, BUFF[0] 0);OLED_ShowChar(0, 2, BUFF[1] 0); BUFF[0] ;BUFF[1] ;HAL_FLASHEx_DATAEEPROM_Unlock();HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_WOR…

《STM32Cube高效开发教程基础篇》- 安装软件/Demo3_1LED

文章目录 下载两个软件安装问题记录在STM32CubeMX中新建项目编辑代码在CudeMX中完成图形化设置在CudeIdea中编码在CLion中编码&#xff08;智能化&#xff09; 效果图 下载两个软件 百度网盘链接&#xff1a;https://pan.baidu.com/s/1uXLWIIVCJbF4ZdvZ7k11Pw 提取码&#xff1…

kubernetes-PV与PVC

一、PV和PVC详解 当前&#xff0c;存储的方式和种类有很多&#xff0c;并且各种存储的参数也需要非常专业的技术人员才能够了解。在Kubernetes集群中&#xff0c;放了方便我们的使用和管理&#xff0c;Kubernetes提出了PV和PVC的概念&#xff0c;这样Kubernetes集群的管理人员就…