在R语言中提取图像主色调并可视化(禁用Imager包)
图片主色调提取与可视化问题解决
问题背景
- 需求:从目标图片提取橙色、黑色、蓝色三种主色调,并通过饼图/柱状图可视化
- 限制:不能使用R语言的
Imager包 - 原尝试代码及输出:
image <- 'https://storage.googleapis.com/du-prd/books/images/9780385547345.jpg' |> readBin("raw", 1e6) |> jpeg::readJPEG() # Extract colors without checking dimensions pixels <- as.matrix(image) kmeans_result <- kmeans(apply(pixels, c(1, 2), mean), centers = 3) colors <- kmeans_result$centers
输出:
[,1] 1 0.07815438 2 0.96756534 3 0.45184408
问题原因
原代码的核心错误是对RGB三通道取均值(apply(pixels, c(1,2), mean)),将彩色图像直接转换为灰度数据,导致kmeans聚类的是灰度值而非真实RGB颜色,自然无法得到预期的彩色主色调。
解决方案
直接对RGB三通道的像素数据进行聚类,步骤如下:
- 解析图片的RGB三维数组(
jpeg::readJPEG返回[高度, 宽度, 通道]格式的三维数组) - 将三维数组转换为每行对应一个像素RGB值的二维数据框
- 对RGB数据执行kmeans聚类(k=3)
- 将聚类中心的RGB值转换为可显示的颜色格式
- 生成可视化图表
修正后完整代码
library(jpeg) library(ggplot2) # 读取图片 image_url <- 'https://storage.googleapis.com/du-prd/books/images/9780385547345.jpg' image <- readBin(image_url, "raw", 1e6) |> readJPEG() # 将三维RGB数组转换为长格式数据框 height <- dim(image)[1] width <- dim(image)[2] pixels <- data.frame( R = as.vector(image[,,1]), G = as.vector(image[,,2]), B = as.vector(image[,,3]) ) # 执行kmeans聚类(固定随机种子保证结果可复现,nstart提升聚类稳定性) set.seed(123) kmeans_result <- kmeans(pixels, centers = 3, nstart = 20) # 将聚类中心的RGB值转换为可显示的颜色(readJPEG返回0-1范围数值,需适配rgb函数要求) cluster_colors <- rgb(kmeans_result$centers[,1], kmeans_result$centers[,2], kmeans_result$centers[,3]) # 统计每个聚类的像素占比 color_stats <- as.data.frame(table(kmeans_result$cluster)) color_stats$color <- cluster_colors names(color_stats) <- c("Cluster", "Count", "Color") color_stats$Percentage <- round(color_stats$Count / sum(color_stats$Count) * 100, 2) # 饼图可视化 ggplot(color_stats, aes(x = "", y = Percentage, fill = Color)) + geom_bar(stat = "identity", width = 1) + coord_polar("y", start = 0) + theme_void() + labs(title = "图片主色调占比饼图") + scale_fill_identity(guide = "legend", labels = paste0(color_stats$Percentage, "%")) # 柱状图可视化 ggplot(color_stats, aes(x = Cluster, y = Percentage, fill = Color)) + geom_bar(stat = "identity") + theme_minimal() + labs(title = "图片主色调占比柱状图", x = "聚类分组", y = "占比(%)") + scale_fill_identity(guide = "legend", labels = paste0(color_stats$Percentage, "%")) + geom_text(aes(label = paste0(Percentage, "%")), vjust = -0.5)
结果说明
运行代码后会得到对应黑色、橙色、蓝色三种预期主色调的聚类结果,饼图和柱状图会直观展示每种颜色的像素占比,解决了原代码仅处理灰度值的问题。
内容的提问来源于stack exchange,提问作者Coder1990
相关产品推荐
相关产品推荐

