【问题标题】:OpenCV: can't get segmentation of image using k-meansOpenCV:无法使用 k-means 分割图像
【发布时间】:2017-01-29 11:13:07
【问题描述】:

在深入探讨我的问题之前,我想让你知道我已经阅读了这个论坛上的其他帖子,但没有人关心我的问题。 特别是,here 帖子回答了“如何做到这一点?”的问题。使用 k-means,虽然我已经知道我必须使用它并且我想知道为什么我的实现不起作用。

我想使用 k-means 算法根据颜色将输入图像的像素分成簇。然后,在完成这样的任务后,我希望每个像素都具有分配给它的集群中心的颜色。 参考 OpenCV 示例和网上检索到的其他资料,我设计了以下代码:

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>

using namespace std;
using namespace cv;


int main( int argc, char** argv )
{

    Mat src = imread( argv[1], 1 );

    // reshape matrix
    Mat resized(src.rows*src.cols, 3, CV_8U);
    int row_counter = 0;

    for(int i = 0; i<src.rows; i++)
    {
        for(int j = 0; j<src.cols; j++)
        {
            Vec3b channels = src.at<Vec3b>(i,j);
            resized.at<char>(row_counter,0) = channels(0);
            resized.at<char>(row_counter,1) = channels(1);
            resized.at<char>(row_counter,2) = channels(2);

            row_counter++;
        }
    }

    //cout << src << endl;

    // change data type
    resized.convertTo(resized, CV_32F);

    // determine termination criteria and number of clusters
    TermCriteria criteria(TermCriteria::COUNT + TermCriteria::EPS, 10, 1.0);
    int K = 8;

    // apply k-means
    Mat labels, centers;
    double compactness = kmeans(resized, K, labels, criteria, 10, KMEANS_RANDOM_CENTERS, centers);

    // change data type in centers
    centers.convertTo(centers, CV_8U);

    // create output matrix
    Mat result = Mat::zeros(src.rows, src.cols, CV_8UC3);

    row_counter = 0;
    int matrix_row_counter = 0;
    while(row_counter < result.rows)
    {
        for(int z = 0; z<result.cols; z++)
        {
            int index = labels.at<char>(row_counter+z, 0);
            //cout << index << endl;
            Vec3b center_channels(centers.at<char>(index,0),centers.at<char>(index,1), centers.at<char>(index,2));
            result.at<Vec3b>(matrix_row_counter, z) = center_channels;
        }

        row_counter += result.cols;
        matrix_row_counter++;
    }

    cout << "Labels " << labels.rows << " " << labels.cols << endl;
    //cvtColor( src, gray, CV_BGR2GRAY );
    //gray.convertTo(gray, CV_32F);

    imshow("Result", result);
    waitKey(0);


    return 0;
}

无论如何,在计算结束时,我只是得到一个黑色图像。 你知道为什么吗? 奇怪的是,如果我将 result 矩阵初始化为

Mat result(src.size(), src.type())

在算法结束时,它将完全显示输入图像,不进行任何分割。

特别是我有两个疑问:

1) 以我的方式将像素的 RGB 值放置在矩阵的每一行 resized 上是否正确?有没有办法在没有循环的情况下做到这一点?

2) 在 k-means 函数完成工作后,centers 的具体内容是什么?它是一个 3 列矩阵,它是否包含簇中心的 RGB 值?

感谢支持。

【问题讨论】:

  • 感谢您的回答。您指出的帖子通过给我一个有效的sn-p代码解决了我的问题。无论如何,如果可能的话,我想知道我哪里出错了,因为我几乎肯定下次会犯同样的错误。有没有可能回答我的两个疑惑?感谢您的支持,如果我要求太多,请原谅:) 我希望您不会将这篇文章视为重复的经典案例 :)
  • 1) 是的,正确,但它们应该是浮点值。你可以在我的帖子中看到如何在没有循环的情况下做到这一点。 2)是的,集群中心的BGR值在float中,你需要转换为uchar。我现在不能更深入地看这个,但我的帖子应该足够清楚

标签: c++ opencv


【解决方案1】:

-下面发布的 OpenCV 程序将用户喜欢的颜色分配给图像中的特定像素值

-ScanImageAndReduceC() 是 OpenCV 中预定义的方法,用于扫描图像的所有像素

-I.atuchar&gt;(10, 10) = 255; 用于访问图像的特定像素值

代码如下:

Mat& ScanImageAndReduceC(Mat& I) {

// 只接受 char 类型的矩阵 CV_Assert(I.depth() == CV_8U);

int channels = I.channels();

int nRows = I.rows;
int nCols = I.cols * 通道;

if (I.isContinuous())
{
    nCols *= nRows;
    nRows = 1;
}

整数 i, j;
uchar* p;
对于 (i = 0; i (i);
    对于 (j = 0; j (10, 10) = 255;
    }
}
返回我;

}

-------主程序-------

在我们的主程序中调用上述方法

diff = ScanImageAndReduceC(diff);

namedWindow("Difference", WINDOW_AUTOSIZE);// 创建一个显示窗口。
imshow("差异", diff); // 在其中显示我们的图像。

等待键(0); // 等待窗口中的击键
返回0;

}

【讨论】:

    猜你喜欢
    • 2017-05-29
    • 2012-03-23
    • 2017-05-23
    • 2023-03-04
    • 2011-07-28
    • 2010-12-11
    • 2019-09-17
    • 2013-12-24
    • 1970-01-01
    相关资源
    最近更新 更多