根据颜色查找图像中的所有对象

时间:2014-05-21 19:07:28

标签: c++ opencv image-processing

我正在寻找一种方法来拍摄图像并通过颜色获取其中所有对象的蒙版。我的目标是能够将类似颜色的对象分成多个层,以便我可以进一步检查每一层。计划是对原始图像使用每个蒙版来创建每个对象中颜色的直方图,并确定与图像中其他对象的相似性。如果某些东西足够相似,它将与其他对象组合形成一个层。

问题是我无法在opencv中找到一个函数来根据颜色连续性查找图像中的所有对象。我确信这样的算法存在,但它似乎在逃避我。有谁知道像这样的算法或函数?

3 个答案:

答案 0 :(得分:1)

我找到的最好的方法是K-means Clustering。这会根据颜色将图像分成不同的图层。它使用k邻居算法来实现。有了这个,我能够有效地将图像分成几个颜色相近的图层。

#define numClusters 7

cv::Mat src = cv::imread("img0.png");

cv::Mat kMeansSrc(src.rows * src.cols, 3, CV_32F);
//resize the image to src.rows*src.cols x 3
//cv::kmeans expects an image that is in rows with 3 channel columns
//this rearranges the image into (rows * columns, numChannels)
for( int y = 0; y < src.rows; y++ )
{
    for( int x = 0; x < src.cols; x++ )
    {
        for( int z = 0; z < 3; z++)
            kMeansSrc.at<float>(y + x*src.rows, z) = src.at<Vec3b>(y,x)[z];
    }
}

cv::Mat labels;
cv::Mat centers;
int attempts = 2;
//perform kmeans on kMeansSrc where numClusters is defined previously as 7
//end either when desired accuracy is met or the maximum number of iterations is reached
cv::kmeans(kMeansSrc, numClusters, labels, cv::TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 8, 1), attempts, KMEANS_PP_CENTERS, centers );

//create an array of numClusters colors
int colors[numClusters];
for(int i = 0; i < numClusters; i++) {
        colors[i] = 255/(i+1);
}

std::vector<cv::Mat> layers;

for(int i = 0; i < numClusters; i++)
{
    layers.push_back(cv::Mat::zeros(src.rows,src.cols,CV_32F));
}

//use the labels to draw the layers
//using the array of colors, draw the pixels onto each label image
for( int y = 0; y < src.rows; y++ )
{
    for( int x = 0; x < src.cols; x++ )
    { 
        int cluster_idx = labels.at<int>(y + x*src.rows,0);
        layers[cluster_idx].at<float>(y, x) = (float)(colors[cluster_idx]);;
    }
}

std::vector<cv::Mat> srcLayers;

//each layer to mask a portion of the original image
//this leaves us with sections of similar color from the original image
for(int i = 0; i < numClusters; i++)
{
    layers[i].convertTo(layers[i], CV_8UC1);
    srcLayers.push_back(cv::Mat());
    src.copyTo(srcLayers[i], layers[i]);
}

答案 1 :(得分:0)

我建议你将图像转换为HSV空间(Hue-Saturation-Value)。然后根据Hue值制作直方图以在线查找阈值,或者在之前定义它们(取决于这是一般性问题还是给定的问题)。

为要形成的每个图层创建单通道图像。 (将它们设置为黑色)

然后使用HSV图像并基于阈值标记图层。您可能还想为值和饱和度添加一些常量阈值(以避免暗区和亮区)

这对你有意义吗?

答案 2 :(得分:0)

我认为你应该按照以下程序进行:

  • 如果图片的细节太多,请为图像添加光线。

  • 找到边

  • 查找所有轮廓

  • 尝试找到每个轮廓的颜色。我们说你想保留所有红色的轮廓。所以,只保留那些红色的轮廓。

  • 找到想要保留的轮廓后,根据想要保留的轮廓创建遮罩图像。

  • 使用蒙版图像,从原始图像中提取所需的对象。