You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于OpenCV+C++提取图像轮廓后,如何获取图像主色调?

提取图像主色调的OpenCV+C++实现方案

嘿,你已经在做轮廓提取了,现在要搞定主色调提取的话,OpenCV里有几种实用的方法,我结合你的场景给你拆解下~

方法一:基于直方图统计的主色调提取

主色调本质就是图像中出现频率最高的颜色,用直方图统计是最直接的方式。如果是针对特定颜色(比如你提到的蓝色),可以先把图像转到HSV空间(比BGR更适合颜色分析),然后筛选出蓝色范围的像素,统计占比;如果是找整体主色,就统计全图颜色的直方图峰值。

针对特定颜色(比如蓝色)的代码示例

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
    Mat image = imread("your_image.jpg");
    if (image.empty()) {
        cout << "无法读取图像!" << endl;
        return -1;
    }

    // 1. 转换到HSV空间
    Mat hsv_image;
    cvtColor(image, hsv_image, COLOR_BGR2HSV);

    // 2. 定义蓝色的HSV范围(可根据实际需求调整)
    Scalar lower_blue = Scalar(90, 50, 50);
    Scalar upper_blue = Scalar(130, 255, 255);

    // 3. 创建蓝色掩码
    Mat blue_mask;
    inRange(hsv_image, lower_blue, upper_blue, blue_mask);

    // 4. 统计蓝色像素占比
    int total_pixels = image.rows * image.cols;
    int blue_pixels = countNonZero(blue_mask);
    float blue_ratio = (float)blue_pixels / total_pixels;

    cout << "蓝色像素占比:" << blue_ratio * 100 << "%" << endl;

    // 如果要结合你已有的轮廓:用轮廓生成掩码,和蓝色掩码做与运算
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    Mat gray;
    cvtColor(image, gray, COLOR_BGR2GRAY);
    findContours(gray, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

    // 创建轮廓掩码
    Mat contour_mask = Mat::zeros(image.size(), CV_8UC1);
    drawContours(contour_mask, contours, -1, Scalar(255), FILLED);

    // 只统计轮廓内的蓝色像素
    Mat masked_blue;
    bitwise_and(blue_mask, contour_mask, masked_blue);
    int contour_blue_pixels = countNonZero(masked_blue);
    float contour_blue_ratio = (float)contour_blue_pixels / countNonZero(contour_mask);

    cout << "轮廓内蓝色像素占比:" << contour_blue_ratio * 100 << "%" << endl;

    return 0;
}

方法二:K-Means聚类提取主色调

如果要自动提取图像(或轮廓区域)的Top N主色,K-Means聚类是更灵活的选择。它会把相似颜色聚成簇,占比最大的簇对应的颜色就是主色调。

代码示例(结合轮廓区域)

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>

using namespace cv;
using namespace std;

// 获取聚类后占比最大的颜色
Scalar getDominantColor(const Mat& image, const Mat& mask = Mat()) {
    // 1. 准备样本数据:把图像像素转成一维数组
    Mat samples;
    if (!mask.empty()) {
        // 只取掩码内的像素
        vector<Vec3b> pixels;
        for (int y = 0; y < image.rows; y++) {
            for (int x = 0; x < image.cols; x++) {
                if (mask.at<uchar>(y, x) == 255) {
                    pixels.push_back(image.at<Vec3b>(y, x));
                }
            }
        }
        if (pixels.empty()) return Scalar(0,0,0);
        Mat(pixels).copyTo(samples);
    } else {
        image.reshape(1, image.rows * image.cols).copyTo(samples);
    }
    samples.convertTo(samples, CV_32F);

    // 2. K-Means聚类(这里设为3类,可调整)
    int k = 3;
    Mat labels, centers;
    kmeans(samples, k, labels, TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 1.0), 3, KMEANS_RANDOM_CENTERS, centers);

    // 3. 统计每个簇的像素数量
    vector<int> cluster_counts(k, 0);
    for (int i = 0; i < labels.rows; i++) {
        int label = labels.at<int>(i);
        cluster_counts[label]++;
    }

    // 4. 找到占比最大的簇对应的颜色
    int max_count = 0;
    int dominant_idx = 0;
    for (int i = 0; i < k; i++) {
        if (cluster_counts[i] > max_count) {
            max_count = cluster_counts[i];
            dominant_idx = i;
        }
    }

    Scalar dominant_color(centers.at<float>(dominant_idx, 0), centers.at<float>(dominant_idx, 1), centers.at<float>(dominant_idx, 2));
    return dominant_color;
}

int main() {
    Mat image = imread("your_image.jpg");
    if (image.empty()) {
        cout << "无法读取图像!" << endl;
        return -1;
    }

    // 先提取轮廓(用你已有的代码)
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    Mat gray;
    cvtColor(image, gray, COLOR_BGR2GRAY);
    findContours(gray, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

    // 创建轮廓掩码
    Mat contour_mask = Mat::zeros(image.size(), CV_8UC1);
    drawContours(contour_mask, contours, -1, Scalar(255), FILLED);

    // 获取轮廓区域的主色调
    Scalar dominant_color = getDominantColor(image, contour_mask);
    cout << "轮廓区域主色调(BGR):" << dominant_color << endl;

    // 如果要获取全图主色,直接传image即可
    // Scalar global_dominant = getDominantColor(image);

    return 0;
}

小提示

  • HSV的颜色范围可以根据实际场景微调,确保蓝色的筛选更准确;
  • K-Means的聚类数k可以按需调整,k=2-5通常能覆盖图像的主要颜色;
  • 结合你已有的轮廓,可以精准提取目标区域的主色调,完全避开背景干扰。

内容的提问来源于stack exchange,提问作者user9469525

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:51:32