我是opencv的新手,我正在尝试查找并保存kmeaned聚簇图像的最大群集。我有:
按照Mercury和Bill the Lizard在以下帖子(Color classification with k-means in OpenCV)中提供的方法对图像进行聚类,
通过查找kmeans输出中最大的标签数来确定最大的群集(bestLables)
尝试在Point2i数组中存储构成最大群集的像素的位置
然而,神秘之处在于我发现自己的存储点数远远少于计数 在尝试找到最大的集群时获得。换句话说:inc<最大。加上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;
}
答案 0 :(得分:3)
你非常接近,但有一些错误。下面的代码应该按预期工作。我还添加了一小段代码来显示分类结果,其中较大群集的像素为红色,另一个为绿色阴影。
int clusters[5];
,因此它会在开头包含随机数,并将其作为累加器进行妥协。我建议改为使用vector<int>
。bestLabels
。而不是bestLables.data[y + x*imlab.cols]
,它应该是bestLables.data[y*imlab.cols + x]
。这导致了您的inc < max
问题。在下面的代码中,我使用vector<int>
来包含索引,因为它更容易看到向量的内容。所以我稍微有点不同地访问bestLabels
,即bestLables[y*imlab.cols + x]
而不是bestLables.data[y*imlab.cols + x]
,但结果是一样的。 Point2i shape[2000];
。我使用了vector<Point>
。请注意,Point
只是Point2i
的typedef。由于您不知道将有多少点,因此最好使用动态数组。如果您知道会有2000分,那么您最好拨打reserve
以避免重新分配,但这不是强制性的。使用Point2i shape[2000];
,如果您的积分超过2000分,那么vector
您将获得安全保障。我在附加点时使用emplace_back
来避免复制(就像使用初始化列表一样)。请注意,Point
的构造函数为(x,y)
,而不是(y,x)
。vector<Point>
您不需要inc
,因为您在最后附加了值。如果您需要inc
来存储最大群集中的点数,只需致电int inc = shape.size();
int cluster = 1
。这是一个错误,您应该使用最大群集的索引对其进行初始化,即int cluster = indx;
。imgRGB
的矢量,但您正在研究实验室。您最好更改名称,但这本身并不是问题。另外,请记住,RGB值作为BGR存储在OpenCV中,而不是RGB(反向顺序)。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;
}