opencv 图片颜色+轮廓识别

目标图片:

  • 1 简单识别图片中出现颜色最多的
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;public class SimpleImageColorRecognizer implements ImageColorRecognizer {@Overridepublic int recognizeDominantColor(String imagePath) throws IOException {File file = new File(imagePath);BufferedImage image = ImageIO.read(file);return recognizeDominantColor(image);}@Overridepublic int recognizeDominantColor(BufferedImage image) {int width = image.getWidth();int height = image.getHeight();int[] colorCount = new int[256 * 256 * 256]; // RGB颜色空间// 遍历图片的每个像素for (int y = 0; y < height; y++) {for (int x = 0; x < width; x++) {int rgb = image.getRGB(x, y);colorCount[rgb & 0x00FFFFFF]++; // 忽略Alpha通道}}// 找到出现次数最多的颜色int maxCount = -1;int dominantColor = 0;for (int i = 0; i < colorCount.length; i++) {if (colorCount[i] > maxCount) {maxCount = colorCount[i];dominantColor = i;}}return dominantColor;}public static void main(String[] args) {try {ImageColorRecognizer recognizer = new SimpleImageColorRecognizer();int dominantColor = recognizer.recognizeDominantColor("D:\\tmp\\b1.png");Color color = new Color(dominantColor);System.out.println("Dominant Color: R=" + color.getRed() + " G=" + color.getGreen() + " B=" + color.getBlue());} catch (IOException e) {e.printStackTrace();}}
}
  • 2、按颜色深浅输出多组颜色
public class MultiColorRecognizer {/*** 使用K-Means聚类算法识别图片中的多种颜色** @param imagePath 图片路径* @param k         聚类的数量(颜色的数量)* @return 返回聚类后的颜色列表(RGB值)* @throws IOException 如果图片无法读取*/public static List<Color> recognizeColors(String imagePath, int k) throws IOException {File file = new File(imagePath);BufferedImage image = ImageIO.read(file);return recognizeColors(image, k);}/*** 使用K-Means聚类算法识别图片中的多种颜色** @param image BufferedImage对象* @param k     聚类的数量(颜色的数量)* @return 返回聚类后的颜色列表(RGB值)*/public static List<Color> recognizeColors(BufferedImage image, int k) {// 提取图片中的所有像素颜色List<int[]> pixels = new ArrayList<>();int width = image.getWidth();int height = image.getHeight();for (int y = 0; y < height; y++) {for (int x = 0; x < width; x++) {int rgb = image.getRGB(x, y);int r = (rgb >> 16) & 0xFF;int g = (rgb >> 8) & 0xFF;int b = rgb & 0xFF;pixels.add(new int[]{r, g, b});}}// 使用K-Means聚类KMeans kmeans = new KMeans(k, pixels);List<int[]> centroids = kmeans.run();// 将聚类中心转换为Color对象List<Color> colors = new ArrayList<>();for (int[] centroid : centroids) {int r = centroid[0];int g = centroid[1];int b = centroid[2];colors.add(new Color(r, g, b));}return colors;}public static void main(String[] args) {try {String imagePath = "D:\\tmp\\b1.png";int k = 5; // 聚类的数量(提取5种主要颜色)List<Color> colors = recognizeColors(imagePath, k);// 输出提取的颜色System.out.println("Extracted Colors:");for (Color color : colors) {System.out.println("R=" + color.getRed() + " G=" + color.getGreen() + " B=" + color.getBlue());}} catch (IOException e) {e.printStackTrace();}}
}
  • 3、颜色+轮廓(依赖opencv_java4110)
public class ColorShapeRecognizer {static {// 直接加载特定路径下的 DLL 文件System.load("D:\\opencv4.11\\build\\java\\x64\\opencv_java4110.dll");}/*** 识别图片中的颜色及其形状** @param imagePath 图片路径* @param k         聚类的数量(颜色的数量)* @return 返回颜色、总轮廓面积和轮廓信息的列表* @throws IOException 如果图片无法读取*/public static List<ColorShapeArea> recognizeColorsAndShapes(String imagePath, int k) throws IOException {// 读取图片Mat image = Imgcodecs.imread(imagePath);if (image.empty()) {throw new IOException("无法读取图片: " + imagePath);}// 将图片转换为RGB格式Mat rgbImage = new Mat();Imgproc.cvtColor(image, rgbImage, Imgproc.COLOR_BGR2RGB);// 提取图片中的所有像素颜色List<int[]> pixels = new ArrayList<>();for (int y = 0; y < rgbImage.rows(); y++) {for (int x = 0; x < rgbImage.cols(); x++) {double[] pixel = rgbImage.get(y, x);int r = (int) pixel[0];int g = (int) pixel[1];int b = (int) pixel[2];pixels.add(new int[]{r, g, b});}}// 使用K-Means聚类KMeans kmeans = new KMeans(k, pixels);List<int[]> centroids = kmeans.run();// 存储颜色、总轮廓面积和轮廓信息List<ColorShapeArea> colorShapeAreas = new ArrayList<>();// 为每种颜色生成掩码并检测形状Mat contourImage = image.clone(); // 复制原图用于绘制轮廓for (int i = 0; i < centroids.size(); i++) {int[] centroid = centroids.get(i);int r = centroid[0];int g = centroid[1];int b = centroid[2];// 定义颜色范围(动态范围,增加容错范围)Scalar lowerBound = new Scalar(Math.max(r - 30, 0), Math.max(g - 30, 0), Math.max(b - 30, 0));Scalar upperBound = new Scalar(Math.min(r + 30, 255), Math.min(g + 30, 255), Math.min(b + 30, 255));// 生成掩码Mat mask = new Mat();Core.inRange(rgbImage, lowerBound, upperBound, mask);// 形态学操作:闭运算去除噪声并连接断开的部分Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(7, 7));Imgproc.morphologyEx(mask, mask, Imgproc.MORPH_CLOSE, kernel);// 检测轮廓List<MatOfPoint> contours = new ArrayList<>();Mat hierarchy = new Mat();Imgproc.findContours(mask, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);// 计算总轮廓面积double totalArea = 0;List<ContourInfo> contourInfos = new ArrayList<>();for (MatOfPoint contour : contours) {double contourArea = Imgproc.contourArea(contour);totalArea += contourArea;// 识别形状ShapeInfo shapeInfo = recognizeShape(contour);// 存储轮廓信息contourInfos.add(new ContourInfo(contourArea, shapeInfo));}// 存储颜色、总轮廓面积和轮廓信息colorShapeAreas.add(new ColorShapeArea(new Color(r, g, b), totalArea, contourInfos));// 在原图上绘制轮廓Imgproc.drawContours(contourImage, contours, -1, new Scalar(r, g, b), 2);}// 按总轮廓面积从大到小排序Collections.sort(colorShapeAreas, Comparator.comparingDouble(ColorShapeArea::getTotalArea).reversed());// 输出排序后的颜色、总轮廓面积和轮廓信息for (ColorShapeArea colorShapeArea : colorShapeAreas) {Color color = colorShapeArea.getColor();double totalArea = colorShapeArea.getTotalArea();List<ContourInfo> contourInfos = colorShapeArea.getContourInfos();System.out.println("Color: R=" + color.getRed() + " G=" + color.getGreen() + " B=" + color.getBlue() +" - Total Area: " + totalArea +" - Contour Count: " + contourInfos.size());for (ContourInfo contourInfo : contourInfos) {double contourArea = contourInfo.getContourArea();ShapeInfo shapeInfo = contourInfo.getShapeInfo();System.out.println("  Contour Area: " + contourArea +" - Shape: " + shapeInfo.getShape() +" - Parameters: " + shapeInfo.getParameters());}}// 保存结果图像(包含轮廓)String outputPath = "D:\\tmp\\contour_image" + System.currentTimeMillis() + ".png";Imgcodecs.imwrite(outputPath, contourImage);System.out.println("轮廓图像已保存至: " + outputPath);// 返回颜色、总轮廓面积和轮廓信息的列表return colorShapeAreas;}/*** 识别轮廓形状** @param contour 轮廓* @return 形状信息(形状名称和参数)*/private static ShapeInfo recognizeShape(MatOfPoint contour) {String shape = "未知";List<String> parameters = new ArrayList<>();MatOfPoint2f contour2f = new MatOfPoint2f(contour.toArray());double peri = Imgproc.arcLength(contour2f, true);MatOfPoint2f approx = new MatOfPoint2f();Imgproc.approxPolyDP(contour2f, approx, 0.04 * peri, true);if (approx.total() == 3) {shape = "三角形";} else if (approx.total() == 4) {// 计算边界框Rect boundingRect = Imgproc.boundingRect(contour);double aspectRatio = (double) boundingRect.width / boundingRect.height;if (aspectRatio >= 0.95 && aspectRatio <= 1.05) {shape = "正方形";} else {shape = "矩形";}} else if (approx.total() > 4) {double area = Imgproc.contourArea(contour);// 识别圆形Point center = new Point();float[] radius = new float[1];Imgproc.minEnclosingCircle(contour2f, center, radius);double circleArea = Math.PI * radius[0] * radius[0];if (Math.abs(area - circleArea) < 0.1 * area) {shape = "圆形";parameters.add("半径: " + radius[0]);} else {// 识别椭圆形RotatedRect ellipse = Imgproc.fitEllipse(contour2f);double majorAxis = Math.max(ellipse.size.width, ellipse.size.height);double minorAxis = Math.min(ellipse.size.width, ellipse.size.height);if (majorAxis > 0 && minorAxis > 0) {double eccentricity = Math.sqrt(1 - Math.pow(minorAxis / majorAxis, 2));if (eccentricity < 0.2) {shape = "椭圆形";parameters.add("长轴: " + majorAxis);parameters.add("短轴: " + minorAxis);}}}}return new ShapeInfo(shape, parameters);}public static void main(String[] args) {try {String imagePath = "D:\\tmp\\b1.png";int k = 15; // 聚类的数量(提取5种主要颜色)List<ColorShapeArea> colorShapeAreas = recognizeColorsAndShapes(imagePath, k);// 处理返回的颜色、总轮廓面积和轮廓信息的列表for (ColorShapeArea colorShapeArea : colorShapeAreas) {Color color = colorShapeArea.getColor();double totalArea = colorShapeArea.getTotalArea();List<ContourInfo> contourInfos = colorShapeArea.getContourInfos();System.out.println("返回的颜色: R=" + color.getRed() + " G=" + color.getGreen() + " B=" + color.getBlue() +" - Total Area: " + totalArea +" - Contour Count: " + contourInfos.size());for (ContourInfo contourInfo : contourInfos) {double contourArea = contourInfo.getContourArea();ShapeInfo shapeInfo = contourInfo.getShapeInfo();System.out.println("  返回的轮廓 Area: " + contourArea +" - Shape: " + shapeInfo.getShape() +" - Parameters: " + shapeInfo.getParameters());}}} catch (IOException e) {e.printStackTrace();}}
}/*** K-Means聚类算法实现*/
class KMeansShapeColorX {private final int k; // 聚类的数量private final List<int[]> data; // 数据点(像素颜色)private final List<int[]> centroids; // 聚类中心public KMeansShapeColorX(int k, List<int[]> data) {this.k = k;this.data = data;this.centroids = new ArrayList<>();initializeCentroids();}/*** 初始化聚类中心*/private void initializeCentroids() {for (int i = 0; i < k; i++) {int[] randomPixel = data.get((int) (Math.random() * data.size()));centroids.add(new int[]{randomPixel[0], randomPixel[1], randomPixel[2]});}}/*** 运行K-Means算法** @return 返回聚类中心*/public List<int[]> run() {boolean changed;do {List<List<int[]>> clusters = assignPointsToClusters();changed = updateCentroids(clusters);} while (changed);return centroids;}/*** 将数据点分配到最近的聚类中心** @return 返回聚类结果*/private List<List<int[]>> assignPointsToClusters() {List<List<int[]>> clusters = new ArrayList<>();for (int i = 0; i < k; i++) {clusters.add(new ArrayList<>());}for (int[] pixel : data) {int closestCentroidIndex = findClosestCentroid(pixel);clusters.get(closestCentroidIndex).add(pixel);}return clusters;}/*** 找到最近的聚类中心** @param pixel 像素颜色* @return 最近的聚类中心索引*/private int findClosestCentroid(int[] pixel) {int closestIndex = 0;double minDistance = Double.MAX_VALUE;for (int i = 0; i < centroids.size(); i++) {double distance = calculateDistance(pixel, centroids.get(i));if (distance < minDistance) {minDistance = distance;closestIndex = i;}}return closestIndex;}/*** 计算两个颜色之间的欧几里得距离** @param a 颜色A* @param b 颜色B* @return 距离*/private double calculateDistance(int[] a, int[] b) {return Math.sqrt(Math.pow(a[0] - b[0], 2) + Math.pow(a[1] - b[1], 2) + Math.pow(a[2] - b[2], 2));}/*** 更新聚类中心** @param clusters 聚类结果* @return 聚类中心是否发生变化*/private boolean updateCentroids(List<List<int[]>> clusters) {boolean changed = false;for (int i = 0; i < clusters.size(); i++) {List<int[]> cluster = clusters.get(i);if (cluster.isEmpty()) {continue;}int[] newCentroid = new int[3];for (int[] pixel : cluster) {newCentroid[0] += pixel[0];newCentroid[1] += pixel[1];newCentroid[2] += pixel[2];}newCentroid[0] /= cluster.size();newCentroid[1] /= cluster.size();newCentroid[2] /= cluster.size();if (!equals(newCentroid, centroids.get(i))) {centroids.set(i, newCentroid);changed = true;}}return changed;}/*** 比较两个颜色是否相同** @param a 颜色A* @param b 颜色B* @return 是否相同*/private boolean equals(int[] a, int[] b) {return a[0] == b[0] && a[1] == b[1] && a[2] == b[2];}
}/*** 存储颜色、总轮廓面积和轮廓信息*/
class ColorShapeArea {private final Color color;private final double totalArea;private final List<ContourInfo> contourInfos;public ColorShapeArea(Color color, double totalArea, List<ContourInfo> contourInfos) {this.color = color;this.totalArea = totalArea;this.contourInfos = contourInfos;}public Color getColor() {return color;}public double getTotalArea() {return totalArea;}public List<ContourInfo> getContourInfos() {return contourInfos;}
}/*** 存储轮廓信息(轮廓面积和形状信息)*/
class ContourInfo {private final double contourArea;private final ShapeInfo shapeInfo;public ContourInfo(double contourArea, ShapeInfo shapeInfo) {this.contourArea = contourArea;this.shapeInfo = shapeInfo;}public double getContourArea() {return contourArea;}public ShapeInfo getShapeInfo() {return shapeInfo;}
}/*** 存储形状信息(形状名称和参数)*/
class ShapeInfo {private final String shape;private final List<String> parameters;public ShapeInfo(String shape, List<String> parameters) {this.shape = shape;this.parameters = parameters;}public String getShape() {return shape;}public List<String> getParameters() {return parameters;}@Overridepublic String toString() {return String.join(", ", parameters);}
}

识别效果:

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

文件系统调用(上) ─── linux第17课

目录 linux 中man 2和man 3的区别 文件内容介绍 C语言文件接口 示例: 输出信息到显示器&#xff0c;你有哪些方法 总结: 系统文件I/O 文件类的系统调用接口介绍 示例 open 函数具体使用哪个,和具体应用场景相关&#xff0c; write read close lseek ,类比C文件相关接…

vue3-element-admin 前后端本地启动联调

一、后端环境准备 1.1、下载地址 gitee 下载地址 1.2、环境要求 JDK 17 1.3、项目启动 克隆项目 git clone https://gitee.com/youlaiorg/youlai-boot.git数据库初始化 执行 youlai_boot.sql 脚本完成数据库创建、表结构和基础数据的初始化。 修改配置 application-dev.y…

证券行业SCA开源风险治理实践

近日&#xff0c;悬镜安全成功中标国内领先的证券公司海通证券软件成分分析工具采购项目&#xff0c;中标产品为源鉴SCA开源威胁管控平台。 海通证券作为国内领先的证券公司之一&#xff0c;当下已基本建成涵盖证券期货经纪、投行、自营、资产管理、私募股权投资、另类投资、融…

JVM内存结构笔记(上)

文章目录 前言运行时数据区域1.程序计数器定义特点总结 2.虚拟机栈2.1 定义局部变量表 ★操作数栈动态链接方法返回地址(方法出口) 2.2 栈内存溢出演示栈内存溢出 java.lang.StackOverflowError 2.3问题辨析1. 垃圾回收是否涉及栈内存&#xff1f;2. 栈内存分配越大越好吗&…

使用 Miniforge3 管理 Python 环境的详细指南(基于最新实践和时效性信息,截至 2025 年)

以下是使用 Miniforge3 管理 Python 环境的详细指南&#xff08;基于最新实践和时效性信息&#xff0c;截至 2025 年&#xff09;&#xff1a; 一、Miniforge3 简介 Miniforge3 是一个轻量级 Conda 环境管理工具&#xff0c;默认使用 conda-forge 软件源&#xff08;社区维护的…

【python|二分|leetcode441】一题搞清楚二分区间问题---闭区间、左闭右开、左开右闭、全开区间

every blog every motto: Although the world is full of suffering&#xff0c; it is full also of the overcoming of it 0. 前言 一题搞清楚二分区间问题—闭区间、左闭右开、左开右闭、全开区间 0.1 题目&#xff1a;Problem: 441. 排列硬币 你总共有 n 枚硬币&#x…

【NLP 34、实践 ⑧ 基于faq知识库和文本匹配算法进行意图识别】

目录 一、demo1_similarity_function.py 二、demo2_bm25.py 三、基于faq知识库和文本匹配算法的意图识别 1.初始化 2.加载BM25模型 3.加载Word2Vec模型 4.文本向量化 5.加载知识库 6.查询方法 7.模型测试 正是江南好时节&#xff0c;落花时节又逢君 —— 25.3.7 一、demo1_sim…

机器人交互系统 部署构建

环境要求 Ubuntu 20.04 或更高版本ROS Noetic 或兼容版本Python 3.8 安装步骤 1. 安装ROS环境&#xff08;如未安装&#xff09; sudo apt update sudo apt install ros-noetic-desktop-full source /opt/ros/noetic/setup.bash2. 创建工作空间并克隆代码 mkdir -p ~/code…

每日一题——两数相加

两数相加 问题描述问题分析解题思路代码实现代码解析注意事项示例运行总结 问题描述 给定两个非空链表&#xff0c;表示两个非负整数。链表中的每个节点存储一个数字&#xff0c;数字的存储顺序为逆序&#xff08;即个位在链表头部&#xff09;。要求将这两个数字相加&#xff…

ResNet50深度解析:原理、结构与PyTorch实现

ResNet50深度解析&#xff1a;原理、结构与PyTorch实现 1. 引言 ResNet&#xff08;残差网络&#xff09;是深度学习领域的一项重大突破&#xff0c;它巧妙解决了深层神经网络训练中的梯度消失/爆炸问题&#xff0c;使得构建和训练更深的网络成为可能。作为计算机视觉领域的里…

政安晨【零基础玩转各类开源AI项目】Wan 2.1 本地部署,基于ComfyUI运行,最强文生视频 图生视频,一键生成高质量影片

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 目录 下载项目 创建虚拟环境 安装项目依赖 尝试运行 依次下载模型 完成 我们今天要使…

每日一题----------String 和StringBuffer和StringBuiler重点

本质&#xff1a;是一个char字符数组存储字符串 总结&#xff1a; 1.如果字符串存在大量的修改操作&#xff0c;一般使用StringBuffer或者StringBuilder。 2.如果字符串存在大量的修改操作&#xff0c;并且单线程的情况&#xff0c;使用StringBuilder。 3.如果字符串存在大…

35.HarmonyOS NEXT Layout布局组件系统详解(二):AutoRow行组件实现原理

HarmonyOS NEXT Layout布局组件系统详解&#xff08;二&#xff09;&#xff1a;AutoRow行组件实现原理 文章目录 HarmonyOS NEXT Layout布局组件系统详解&#xff08;二&#xff09;&#xff1a;AutoRow行组件实现原理1. AutoRow组件概述2. AutoRow组件接口定义3. AutoRow组件…

Java 集合框架大师课:集合框架源码解剖室(五)

&#x1f525;Java 集合框架大师课&#xff1a;集合框架源码解剖室&#xff08;五&#xff09; &#x1f4a3; 警告&#xff1a;本章包含大量 裸码级硬核分析&#xff0c;建议搭配咖啡因饮料阅读&#xff01;☕️ 第一章 ArrayList 的扩容玄学 1.1 动态扩容核心代码大卸八块 …

Kubernetes服务部署 —— Kafka

1、简介 Kafka和zookeeper是两种典型的有状态的应用集群服务。首先kafka和zookeeper都需要存储盘来保存有状态信息&#xff1b;其次kafka和zookeeper每一个实例都需要有对应的实例Id (Kafka需broker.id, zookeeper需要my.id) 来作为集群内部每个成员的标识&#xff0c;集群内节…

计算机网络基础知识

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

电脑的写字板如何使用?

打开写字板&#xff1a; 直接按一下键盘上的win R 键&#xff0c;然后输入&#xff1a;write &#xff0c; 再按一下回车 , 即可打开写字板 可以在里面写文字 和 插入图片等… &#xff0c; 如下所示&#xff1a; 保存写字板内容&#xff1a; 当我们写好了之后&#xff0c;…

用vector实现栈的功能

要注意pop_back和back()的区别 #include <bits/stdc.h> using namespace std;void Push(vector<int> &v,int x) {v.push_back(x); }void Top(vector<int> &v) {if(!v.empty()){cout<<v.back()<<endl;// v.pop_back();}else {cout<&l…

SegMAN模型详解及代码复现

SegMAN模型概述 模型背景 在深入探讨SegMAN模型之前&#xff0c;我们需要了解其研究背景。在SegMAN出现之前&#xff0c;计算机视觉领域的研究主要集中在以下几个方面&#xff1a; 手工制作方法&#xff0c;如SIFT基于卷积神经网络(CNN)的方法&#xff0c;如STN和PTN对平移、…

基于粒子群算法的配电网重构

一、配电网重构原理 定义&#xff1a; 配电网重构是指在满足运行约束的前提下&#xff0c;通过改变开关状态优化配电网性能&#xff0c;提高系统的经济效益和运行效率。 拓扑约束&#xff1a; 配电网必须保持径向拓扑&#xff0c;避免环网或孤岛。采用算法控制开关状态的选择&…