gpt4 book ai didi

c++ - 如何在 opencv 中访问特定的 kmeans 集群

转载 作者:搜寻专家 更新时间:2023-10-31 01:39:17 26 4
gpt4 key购买 nike

我是 opencv 的新手,我正在尝试查找并保存 kmeaned 聚类图像的最大聚类。我有:

  • 按照 Mercury 和 Bill the Lizard 在以下帖子 ( Color classification with k-means in OpenCV ) 中提供的方法对图像进行聚类,

  • 通过从 kmeans 输出 (bestLables) 中找到最大的标签数来确定最大的集群

  • 试图将构成最大簇的像素的位置存储在一个Point2i数组中

然而,奇怪的是,我发现自己的存储点数明显少于计数在试图找到最大的簇时获得。换句话说:inc < max。加上 inc 给出的数字甚至不对应于任何其他集群的点数。

我做错了什么?还是有更好的方法来做我想做的事情?任何意见都将不胜感激。在此先感谢您的宝贵帮助!!

#include <iostream>
#include "opencv2/opencv.hpp"
#include<opencv2/highgui/highgui.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

using namespace cv;
using namespace std;



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

Mat img = imread("pic.jpg", CV_LOAD_IMAGE_COLOR);

if (!img.data)
{
cout << "Could not open or find the image" << std::endl;
return -1;
}


//imshow("img", img);

Mat imlab;
cvtColor(img, imlab, CV_BGR2Lab);

/* Cluster image */
vector<cv::Mat> imgRGB;
int k = 5;
int n = img.rows *img.cols;
Mat img3xN(n, 3, CV_8U);

split(imlab, imgRGB);

for (int i = 0; i != 3; ++i)
imgRGB[i].reshape(1, n).copyTo(img3xN.col(i));

img3xN.convertTo(img3xN, CV_32F);

Mat bestLables;
kmeans(img3xN, k, bestLables, cv::TermCriteria(), 10, cv::KMEANS_RANDOM_CENTERS);

/*bestLables= bestLables.reshape(0,img.rows);
cv::convertScaleAbs(bestLables,bestLables,int(255/k));
cv::imshow("result",bestLables);*/

/* Find the largest cluster*/
int max = 0, indx= 0, id = 0;
int clusters[5];

for (int i = 0; i < bestLables.rows; i++)
{
id = bestLables.at<int>(i, 0);
clusters[id]++;

if (clusters[id] > max)
{
max = clusters[id];
indx = id;
}
}

/* save largest cluster */
int cluster = 1, inc = 0;
Point2i shape[2000];

for (int y = 0; y < imlab.rows; y++)
{
for (int x = 0; x < imlab.cols; x++)
{
if (bestLables.data[y + x*imlab.cols] == cluster) shape[inc++] = { y, x };
}
}


waitKey(0);


return 0;
}

最佳答案

你很接近,但有一些错误。下面的代码应该按预期工作。我还添加了一小段代码来显示分类结果,其中较大簇的像素为红色,另一个为绿色。

  1. 您从未初始化 int clusters[5]; ,因此它将在开头包含随机数,从而将其作为累加器妥协。我建议使用 vector<int>相反。
  2. 您访问 bestLabels有错误的索引。而不是 bestLables.data[y + x*imlab.cols] ,应该是bestLables.data[y*imlab.cols + x] .那导致了你的inc < max问题。在下面的代码中,我使用了 vector<int>包含索引,因为更容易看到 vector 的内容。所以我访问bestLabels有点不同,即 bestLables[y*imlab.cols + x]而不是 bestLables.data[y*imlab.cols + x] ,但结果是一样的。
  3. 你有Point2i shape[2000]; .我用了 vector<Point> .注意 Point只是 Point2i 的类型定义.由于您不知道那里会有多少点,因此最好使用动态数组。如果你知道会有,比方说,2000分,你最好打电话reserve以避免重新分配,但这不是强制性的。与 Point2i shape[2000];如果你有超过 2000 分,你就会出界,带有 vector你安全了。我用了emplace_back在附加点时避免复制(就像您对初始化列表所做的那样)。请注意 Point 的构造函数是(x,y) , 不是 (y,x) .
  4. 使用 vector<Point>你不需要 inc ,因为您在末尾附加了值。如果您需要inc要存储最大簇中的点数,只需调用 int inc = shape.size();
  5. 你初始化了int cluster = 1 .这是一个错误,您应该使用最大集群的索引对其进行初始化,即 int cluster = indx; .
  6. 你称平面 vector 为imgRGB ,但你在实验室工作。您最好更改名称,但这本身不是问题。另外,请记住,RGB 值在 OpenCV 中存储为 BGR,而不是 RGB(倒序)。
  7. 我更喜欢 Mat1b , Mat3b等... 可能超过 Mat .它允许更容易访问并且更具可读性(在我看来)。这不是问题,但您会在我的代码中看到这一点。

开始吧:

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;

int main(int argc, char** argv)
{
Mat3b img = imread("path_to_image");

if (!img.data)
{
std::cout << "Could not open or find the image" << std::endl;
return -1;
}

Mat3b imlab;
cvtColor(img, imlab, CV_BGR2Lab);

/* Cluster image */
vector<cv::Mat3b> imgRGB;
int k = 5;
int n = img.rows * img.cols;
Mat img3xN(n, 3, CV_8U);

split(imlab, imgRGB);

for (int i = 0; i != 3; ++i)
imgRGB[i].reshape(1, n).copyTo(img3xN.col(i));

img3xN.convertTo(img3xN, CV_32F);

vector<int> bestLables;
kmeans(img3xN, k, bestLables, cv::TermCriteria(), 10, cv::KMEANS_RANDOM_CENTERS);

/* Find the largest cluster*/
int max = 0, indx= 0, id = 0;
vector<int> clusters(k,0);

for (size_t i = 0; i < bestLables.size(); i++)
{
id = bestLables[i];
clusters[id]++;

if (clusters[id] > max)
{
max = clusters[id];
indx = id;
}
}

/* save largest cluster */
int cluster = indx;

vector<Point> shape;
shape.reserve(2000);

for (int y = 0; y < imlab.rows; y++)
{
for (int x = 0; x < imlab.cols; x++)
{
if (bestLables[y*imlab.cols + x] == cluster)
{
shape.emplace_back(x, y);
}
}
}

int inc = shape.size();

// Show results
Mat3b res(img.size(), Vec3b(0,0,0));
vector<Vec3b> colors;
for(int i=0; i<k; ++i)
{
if(i == indx) {
colors.push_back(Vec3b(0, 0, 255));
} else {
colors.push_back(Vec3b(0, 255 / (i+1), 0));
}
}

for(int r=0; r<img.rows; ++r)
{
for(int c=0; c<img.cols; ++c)
{
res(r,c) = colors[bestLables[r*imlab.cols + c]];
}
}

imshow("Clustering", res);
waitKey(0);

return 0;
}

关于c++ - 如何在 opencv 中访问特定的 kmeans 集群,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31439355/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com