目标图片:

- 1 简单识别图片中出现颜色最多的
java
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 {
@Override
public int recognizeDominantColor(String imagePath) throws IOException {
File file = new File(imagePath);
BufferedImage image = ImageIO.read(file);
return recognizeDominantColor(image);
}
@Override
public 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、按颜色深浅输出多组颜色
java
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)
java
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;
}
@Override
public String toString() {
return String.join(", ", parameters);
}
}
识别效果:
