Mean shift 算法是基于核密度估计的爬山算法,可用于聚类、图像分割、跟踪等。本文利用OpenCV进行图片种物体识别。
1.确认类函数是否正确:
cv::MatND ColorHistogram::getHueHistogram(const cv::Mat &image, int minSaturation = 0)
{
cv::MatND hist;
// Convert to Lab color space
cv::Mat hue;
cv::cvtColor(image, hue, CV_BGR2HSV);
cv::Mat mask;
if (minSaturation >0)
{
std::vector<cv::Mat>v;
cv::split(hue, v);
cv::threshold(v[1], mask, minSaturation, 255, cv::THRESH_BINARY);
}
// Prepare arguments for a 1D hue histogram
hranges[0] = 0.0;
hranges[1] = 180.0;
channels[0] = 0; // the hue channel
// Compute histogram
cv::calcHist(&hue,
1, // histogram of 1 image only
channels, // the channel used
mask, // no mask is used
hist, // the resulting histogram
1, // it is a 1D histogram
histSize, // number of bins
ranges // pixel value range
);
return hist;
}
/***************************************************************/
void ContentFinder::setThreshold(float t)
{
threshold = t;
}
float ContentFinder::getThreshold()
{
return threshold;
}
void ContentFinder::setHistogram(const cv::MatND &h)
{
histogram = h;
cv::normalize(histogram, histogram, 1.0);
}
cv::Mat ContentFinder::find(const cv::Mat& image, float minValue, float maxValue, int *channels, int dim)
{
cv::Mat result;
hranges[0] = minValue;
hranges[1] = maxValue;
for (int i = 0; i < dim; i++)
{
this->channels[i] = channels[i];
}
cv::calcBackProject(&image,
1,
channels,
histogram,
result,
ranges,
255.0
);
if (threshold > 0.0)
{
cv::threshold(result, result, 255 * threshold, 255, cv::THRESH_BINARY);
}
return result;
}
2.进行过程处理:
void OpenCVQtGui::MeanShift_clicked()
{
cv::Mat Result;
cv::Mat ImageROI;
cv::Mat colors = cv::imread("Cup.jpg"); //Put Girl.jpg into the same pat
ImageROI = colors(cv::Rect(120, 80, 100, 120));
cv::rectangle(colors, cv::Rect(120, 80, 100, 120), cv::Scalar(0, 0, 255));
/*显示第一张图片*/
cv::imshow("1.ImageROI1", colors);
//获取色调通道直方图
int minSat = 30;
cv::MatND hist = Chist.getHueHistogram(ImageROI,minSat);
finder.setHistogram(hist);
/*处理第二张图片*/
cv::Mat image2 = image.clone();
cv::Mat hsv;
cv::cvtColor(image2, hsv, CV_BGR2HSV);
/*分离图像通道*/
std::vector<cv::Mat>v;
cv::split(hsv, v);
/*消除饱和度较低的像素点*/
cv::threshold(v[1], v[1], minSat, 255, cv::THRESH_BINARY);
cv::imshow("2.消除饱和度较低的像素点", v[1]);
/*进行直方图反投影*/
finder.setHistogram(hist);
finder.setThreshold(0.3f);
int ch[1] = { 0};
Result = finder.find(hsv, 0.0f, 180.0f, ch, 1);
cv::imshow("3.进行直方图反投影", Result);
/*利用位运算消除低饱和度像素*/
cv::bitwise_and(Result, v[1], Result);
cv::imshow("4.利用位运算消除低饱和度像素", Result);
/*得到反投影直方图概率图像*/
finder.setThreshold(-0.1f);
Result = finder.find(hsv, 0.0f, 180.0f, ch, 1);
cv::bitwise_and(Result, v[1], Result);
cv::imshow("5.利用位运算消除低饱和度像素", Result);
cv::Rect rect(120, 80, 100, 120);
cv::rectangle(image2, rect, cv::Scalar(0,0,255));
cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER,10,0.01);
cv::meanShift(Result, rect, criteria);
cv::rectangle(image2, rect, cv::Scalar(0, 255, 0));
Result = image2;
cvtColor(Result, Result, CV_BGR2RGB);
QImage img1 = QImage((const unsigned char*)(Result.data), Result.cols, Result.rows, QImage::Format_RGB888);
ui.label_2->setPixmap(QPixmap::fromImage(img1));
ui.label_2->resize(QSize(img1.width(), img1.height()));
3.处理效果:
原图