您的位置:首页 > 运维架构

Opencv直方图反投影检测颜色

2017-10-03 15:25 267 查看
本文按照OpenCV2计算机视觉编程手册书写代码。

对于书中一些地方,为了实现更好的效果有改动。

首先是第一个类ColorHistogram

#pragma once
#if !defined COLHISTOGRAM
#define COLHISTOGRAM

#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>

class ColorHistogram {

private:

int histSize[3];
float hranges[2];
const float* ranges[3];
int channels[3];

public:

ColorHistogram() {

histSize[0] = histSize[1] = histSize[2] = 256;
hranges[0] = 0.0;
hranges[1] = 256.0;
ranges[0] = hranges;
ranges[1] = hranges;
ranges[2] = hranges;
channels[0] = 0;
channels[1] = 1;
channels[2] = 2;
}

void setSize(int size) {

histSize[0] = histSize[1] = histSize[2] = size;
}

cv::Mat getHistogram(const cv::Mat &image) {

cv::Mat hist;

hranges[0] = 0.0;
hranges[1] = 256.0;
channels[0] = 0;
channels[1] = 1;
channels[2] = 2;

cv::calcHist(&image,
1,
channels,
cv::Mat(),
hist,
3,
histSize,
ranges
);
return hist;
}

cv::SparseMat getSparseHistogram(const cv::Mat &image) {

cv::SparseMat hist(3,
histSize,
CV_32F);

hranges[0] = 0.0;
hranges[1] = 256.0;
channels[0] = 0;
channels[1] = 1;
channels[2] = 2;

cv::calcHist(&image,
1,
channels,
cv::Mat(),
hist,
3,
histSize,
ranges
);
return hist;
}

cv::Mat getHueHistogram(const cv::Mat &image,
int minSaturation = 0) {
cv::Mat hist;

cv::Mat hsv;
cv::cvtColor(image, hsv, CV_BGR2HSV);

cv::Mat mask;

if (minSaturation>0) {

std::vector<cv::Mat> v;
cv::split(hsv, v);

cv::threshold(v[1], mask, minSaturation, 255,
cv::THRESH_BINARY);
}

hranges[0] = 0.0;
hranges[1] = 180.0;
channels[0] = 0;

cv::calcHist(&hsv,
1,
channels,
mask,
hist,
1,
histSize,
ranges
);
return hist;
}

// Computes the 2D ab histogram.
// BGR source image is converted to Lab
cv::Mat getabHistogram(const cv::Mat &image) {

cv::Mat hist;

// Convert to Lab color space
cv::Mat lab;
cv::cvtColor(image, lab, CV_BGR2Lab);

// Prepare arguments for a 2D color histogram
hranges[0] = 0;
hranges[1] = 256.0;
channels[0] = 1; // the two channels used are ab
channels[1] = 2;

// Compute histogram
cv::calcHist(&lab,
1,          // histogram of 1 image only
channels,       // the channel used
cv::Mat(),      // no mask is used
hist,           // the resulting histogram
2,          // it is a 2D histogram
histSize,       // number of bins
ranges          // pixel value range
);
return hist;
}
};
#endif


第二个类ContentFinder

#pragma once
#if !defined OFINDER
#define OFINDER

#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>

class ContentFinder {

private:

// histogram parameters
float hranges[2];
const float* ranges[3];
int channels[3];

float threshold;           // decision threshold
cv::Mat histogram;         // histogram can be sparse 输入直方图
cv::SparseMat shistogram;  // or not
bool isSparse;

public:

ContentFinder() : threshold(0.1f), isSparse(false) {

// in this class,
// all channels have the same range
ranges[0] = hranges;
ranges[1] = hranges;
ranges[2] = hranges;

4000
}

// Sets the threshold on histogram values [0,1]
void setThreshold(float t) {

threshold = t;
}

// Gets the threshold
float getThreshold() {

return threshold;
}

// Sets the reference histogram
void setHistogram(const cv::Mat& h) {

isSparse = false;
cv::normalize(h, histogram, 1.0);
}

// Sets the reference histogram
void setHistogram(const cv::SparseMat& h) {

isSparse = true;
cv::normalize(h, shistogram, 1.0, cv::NORM_L2);
}

// All channels used, with range [0,256]
cv::Mat find(const cv::Mat& image) {

cv::Mat result;

hranges[0] = 0.0;   // default range [0,256]
hranges[1] = 256.0;
channels[0] = 0;        // the three channels
channels[1] = 1;
channels[2] = 2;

return find(image, hranges[0], hranges[1], channels);
}

// Finds the pixels belonging to the histogram
cv::Mat find(const cv::Mat& image, float minValue, float maxValue, int *channels) {

cv::Mat result;

hranges[0] = minValue;
hranges[1] = maxValue;

if (isSparse) { // call the right function based on histogram type

for (int i = 0; i<shistogram.dims(); i++)
this->channels[i] = channels[i];

cv::calcBackProject(&image,
1,            // we only use one image at a time
channels,     // vector specifying what histogram dimensions belong to what image channels
shistogram,   // the histogram we are using
result,       // the resulting back projection image
ranges,       // the range of values, for each dimension
255.0         // the scaling factor is chosen such that a histogram value of 1 maps to 255
);

}
else {

for (int i = 0; i<histogram.dims; i++)
this->channels[i] = channels[i];
//某对象的this指针,指向被调用函数所在的对象,此处对象为ContentFinder类
//this->channels[i]即ContentFinder类的私有成员channels[3]
//对ContentFinder类各成员的访问均通过this进行
cv::calcBackProject(&image,
1,            // we only use one image at a time
channels,     // 向量表示哪个直方图维度属于哪个图像通道
histogram,    // 用到的直方图
result,       // 反向投影的图像
ranges,       // 每个维度值的范围
255.0         // 选用的换算系数
);
}
// Threshold back projection to obtain a binary image阈值分割反向投影图像得到二值图
if (threshold>0.0)// 设置的阈值>0时,才进行阈值分割
cv::threshold(result, result, 255.0*threshold, 255.0, cv::THRESH_BINARY);
return result;
}
};
#endif


主程序(main):

#include <cv.h>
#include <highgui.h>
#include <opencv2\opencv.hpp>
#include "ColorHistogram.h"
#include "ContentFinder.h"
using namespace std;
using namespace cv;

/// 全局变量的声明与初始化
const int alpha_slider_max = 99;
int alpha_slider;

cv::Mat image;
cv::Mat imageROI;
ContentFinder finder;
cv::Mat result1;
ColorHistogram hc;
VideoCapture cap(1);
Mat color;

void on_trackbar(int, void*)
{

float a = float(alpha_slider / 100.0);
finder.setThreshold(a);
while (true) {

cap >> color;
namedWindow("1");
imshow("1", color);
result1 = finder.find(color);
Mat res;
Mat element5(3, 3, CV_8U, Scalar(1));
morphologyEx(result1, res, MORPH_CLOSE, element5);
blur(res, res, Size(2, 2));
cv::namedWindow("Color Detection Result");
cv::imshow("Color Detection Result", res);
char c = waitKey(33);
if (c == 27) break;
}
return;
}

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

image = cv::imread("E:\\ProgramProject\\1.png");
if (!image.data)
return 0;
//cv::Mat imageROI;
imageROI = image(cv::Rect(0, 0, 30, 24));
hc.setSize(4);
cv::Mat shist = hc.getHistogram(imageROI);
finder.setHistogram(shist);
/// 初始化为零
alpha_slider = 9;

/// 创建窗体
namedWindow("Rate");

/// 在创建的窗体中创建一个滑动条控件
char TrackbarName[50];
sprintf(TrackbarName, "Alpha x %d", alpha_slider);

createTrackbar(TrackbarName, "Rate", &alpha_slider, alpha_slider_max, on_trackbar);

/// 结果在回调函数中显示
on_trackbar(alpha_slider, 0);
return 0;
}


书中的
histSize[0] = histSize[1] = histSize[2] = 256;


并没有设置修改方法,这里设置了

void setSize(int size) {

histSize[0] = histSize[1] = histSize[2] = size;
}


这一方法用于修改bin值,一举解决了按照书上代码有时无法显示图像的问题。

另外,通过滑动条可以动态调整识别阈值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: