目标图片:
- 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);}
}
识别效果: