在R中循环处理RGB帧矩阵的汇总统计与K-means聚类及问题解决
视频帧RGB矩阵批量分析与K-means聚类问题解决
问题梳理
- 已将视频分割为125帧,每帧包含R/G/B三个二维颜色矩阵,需要批量完成:
- 每个颜色矩阵的汇总统计
- K-means聚类分析
- 手动处理单帧红色通道时遇到两个问题:
- 聚类结果里一个簇占886个数据点,其余仅个位数,看不懂结果含义
- 用
fviz_cluster()绘图时触发报错:Error in prcomp.default(data, scale = FALSE, center = FALSE) : cannot rescale a constant/zero column to unit variance
问题根源与解决办法
1. 颜色矩阵格式错配是核心问题
你现在用的Frame1[["redChannel"]]是二维图像矩阵(行对应图像高度,列对应宽度),但K-means和factoextra工具默认要求的是「行=样本,列=特征」的数据结构。直接喂图像矩阵的话,相当于把每一行像素当成一个样本,这完全不符合我们要对单个像素颜色聚类的逻辑。
修正步骤:
把二维颜色矩阵转成一维像素向量,再包装成单列数据框(每个行对应一个像素的颜色值):
# 处理单帧红色通道:二维矩阵转单列数据框 df_red <- as.data.frame(as.vector(Frame1[["redChannel"]])) colnames(df_red) <- "red_value"
2. 聚类结果异常的原因与修正
之前的超大簇是因为对「行像素组」聚类,大部分行的像素分布相似,所以挤在一个簇里。换成一维像素向量后,聚类是对所有像素的颜色值分组,结果会对应不同亮度区间的像素数量(比如暗红色像素多,对应簇的大小就大)。
重新跑K-means:
# 先确定最优簇数(看WSS曲线的拐点) fviz_nbclust(df_red, kmeans, method = "wss") # 用最优簇数跑聚类(比如3簇) km_red <- kmeans(df_red, centers = 3, nstart = 25) # 查看结果 print(km_red)
3. fviz_cluster()绘图报错解决
报错是因为原二维矩阵里有全相同值的列(比如图像某一列像素颜色完全一致),导致PCA降维失败。换成单列数据框后,要调整参数适配单特征数据:
fviz_cluster(km_red, data = df_red, stand = FALSE, geom = "point")
stand = FALSE:单特征不需要标准化,关闭避免报错geom = "point":只画散点,避免默认文本重叠
批量处理125帧的循环写法
假设所有帧存在列表frame_list里(比如frame_list[[1]]就是Frame1,包含redChannel/greenChannel/blueChannel),用嵌套循环批量处理:
# 加载依赖包 library(factoextra) library(cluster) # 初始化结果存储列表 stats_results <- list() cluster_results <- list() # 循环处理每帧 for (i in 1:125) { current_frame <- frame_list[[i]] frame_stats <- list() frame_clusters <- list() # 循环处理每个颜色通道 for (channel in c("redChannel", "greenChannel", "blueChannel")) { # 转换数据格式 channel_data <- as.data.frame(as.vector(current_frame[[channel]])) colnames(channel_data) <- channel # 计算汇总统计 channel_stats <- data.frame( 最小值 = min(channel_data[[1]]), 最大值 = max(channel_data[[1]]), 平均值 = mean(channel_data[[1]]), 中位数 = median(channel_data[[1]]), 标准差 = sd(channel_data[[1]]), 像素总数 = nrow(channel_data) ) frame_stats[[channel]] <- channel_stats # K-means聚类(这里用3簇,可根据WSS结果调整) km <- kmeans(channel_data, centers = 3, nstart = 25) frame_clusters[[channel]] <- km } # 存储当前帧的结果 stats_results[[paste0("Frame", i)]] <- frame_stats cluster_results[[paste0("Frame", i)]] <- frame_clusters } # 查看第1帧红色通道的统计结果 print(stats_results[["Frame1"]][["redChannel"]]) # 查看第1帧红色通道的聚类结果 print(cluster_results[["Frame1"]][["redChannel"]])
额外提示
- 如果想自动确定每通道的最优簇数,可以在循环里加入拐点判断:
# 找WSS曲线的拐点对应的簇数 nb_clust <- fviz_nbclust(channel_data, kmeans, method = "wss")$data %>% filter(diff(wss) == min(diff(wss))) %>% pull(clusters) km <- kmeans(channel_data, centers = nb_clust, nstart = 25) - 汇总统计可以根据需求加更多指标,比如四分位数、偏度等。
内容的提问来源于stack exchange,提问作者Yogesh Selvakumar
相关产品推荐
相关产品推荐

