Opencv测试用例
Chapter03
1、colorDetection.cpp
结果
测试代码
头文件colordetector.h
#if !defined COLORDETECT
#define COLORDETECT
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
class ColorDetector {
private:
// minimum acceptable distance
int maxDist;
// target color
cv::Vec3b target;
// image containing color converted image
cv::Mat converted;
bool useLab;
// image containing resulting binary map
cv::Mat result;
public:
// empty constructor
// default parameter initialization here
ColorDetector() : maxDist(100), target(0, 0, 0), useLab(false) {}
// extra constructor for Lab color space example
ColorDetector(bool useLab) : maxDist(100), target(0, 0, 0), useLab(useLab) {}
// full constructor
ColorDetector(uchar blue, uchar green, uchar red, int mxDist = 100, bool useLab = false) : maxDist(mxDist), useLab(useLab) {
// target color
setTargetColor(blue, green, red);
}
// Computes the distance from target color.
int getDistanceToTargetColor(const cv::Vec3b& color) const {
return getColorDistance(color, target);
}
// Computes the city-block distance between two colors.
int getColorDistance(const cv::Vec3b& color1, const cv::Vec3b& color2) const {
return abs(color1[0] - color2[0]) +
abs(color1[1] - color2[1]) +
abs(color1[2] - color2[2]);
// Or:
// return static_cast<int>(cv::norm<int,3>(cv::Vec3i(color[0]-color2[0],color[1]-color2[1],color[2]-color2[2])));
// Or:
// cv::Vec3b dist;
// cv::absdiff(color,color2,dist);
// return cv::sum(dist)[0];
}
// Processes the image. Returns a 1-channel binary image.
cv::Mat process(const cv::Mat &image);
cv::Mat operator()(const cv::Mat &image) {
cv::Mat input;
if (useLab) { // Lab conversion
cv::cvtColor(image, input, cv::COLOR_BGR2Lab);
}
else {
input = image;
}
cv::Mat output;
// compute absolute difference with target color
cv::absdiff(input, cv::Scalar(target), output);
// split the channels into 3 images
std::vector<cv::Mat> images;
cv::split(output, images);
// add the 3 channels (saturation might occurs here)
output = images[0] + images[1] + images[2];
// apply threshold
cv::threshold(output, // input image
output, // output image
maxDist, // threshold (must be < 256)
255, // max value
cv::THRESH_BINARY_INV); // thresholding type
return output;
}
// Getters and setters
// Sets the color distance threshold.
// Threshold must be positive, otherwise distance threshold
// is set to 0.
void setColorDistanceThreshold(int distance) {
if (distance < 0)
distance = 0;
maxDist = distance;
}
// Gets the color distance threshold
int getColorDistanceThreshold() const {
return maxDist;
}
// Sets the color to be detected
// given in BGR color space
void setTargetColor(uchar blue, uchar green, uchar red) {
// BGR order
target = cv::Vec3b(blue, green, red);
if (useLab) {
// Temporary 1-pixel image
cv::Mat tmp(1, 1, CV_8UC3);
tmp.at<cv::Vec3b>(0, 0) = cv::Vec3b(blue, green, red);
// Converting the target to Lab color space
cv::cvtColor(tmp, tmp, cv::COLOR_BGR2Lab);
target = tmp.at<cv::Vec3b>(0, 0);
}
}
// Sets the color to be detected
void setTargetColor(cv::Vec3b color) {
target = color;
}
// Gets the color to be detected
cv::Vec3b getTargetColor() const {
return target;
}
};
#endif
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "colordetector.h"
static int test()
{
// 1. Create image processor object
ColorDetector cdetect;
// 2. Read input image
std::string path_boldt = "F:/images/boldt.jpg";
cv::Mat image= cv::imread(path_boldt);
if (image.empty())
return 0;
cv::namedWindow("Original Image");
cv::imshow("Original Image", image);
// 3. Set input parameters
cdetect.setTargetColor(230,190,130); // here blue sky
// 4. Process the image and display the result
cv::namedWindow("result");
cv::Mat result = cdetect.process(image);
cv::imshow("result",result);
// or using functor
// here distance is measured with the Lab color space
ColorDetector colordetector(230, 190, 130, // color
45, true); // Lab threshold
cv::namedWindow("result (functor)");
result = colordetector(image);
cv::imshow("result (functor)",result);
// testing floodfill
cv::floodFill(image, // input/ouput image
cv::Point(100, 50), // seed point
cv::Scalar(255, 255, 255), // repainted color
(cv::Rect*)0, // bounding rectangle of the repainted pixel set
cv::Scalar(35, 35, 35), // low and high difference threshold
cv::Scalar(35, 35, 35), // most of the time will be identical
cv::FLOODFILL_FIXED_RANGE); // pixels are compared to seed color
cv::namedWindow("Flood Fill result");
result = colordetector(image);
cv::imshow("Flood Fill result", image);
// Creating artificial images to demonstrate color space properties
cv::Mat colors(100, 300, CV_8UC3, cv::Scalar(100, 200, 150));
cv::Mat range= colors.colRange(0, 100);
range = range + cv::Scalar(10, 10, 10);
range = colors.colRange(200, 300);
range = range + cv::Scalar(-10, -10, 10);
cv::namedWindow("3 colors");
cv::imshow("3 colors", colors);
cv::Mat labImage(100, 300, CV_8UC3, cv::Scalar(100, 200, 150));
cv::cvtColor(labImage, labImage, cv::COLOR_RGB2Lab);
range = colors.colRange(0, 100);
range = range + cv::Scalar(10, 10, 10);
range = colors.colRange(200, 300);
range = range + cv::Scalar(-10, -10, 10);
cv::cvtColor(labImage, labImage, cv::COLOR_Lab2BGR);
cv::namedWindow("3 colors (Lab)");
cv::imshow("3 colors (Lab)", colors);
// brightness versus luminance
cv::Mat grayLevels(100, 256, CV_8UC3);
for (int i = 0; i < 256; i++) {
grayLevels.col(i) = cv::Scalar(i, i, i);
}
range = grayLevels.rowRange(50, 100);
cv::Mat channels[3];
cv::split(range, channels);
channels[1] = 128;
channels[2] = 128;
cv::merge(channels, 3, range);
cv::cvtColor(range, range, cv::COLOR_Lab2BGR);
cv::namedWindow("Luminance vs Brightness");
cv::imshow("Luminance vs Brightness", grayLevels);
cv::waitKey();
return 0;
}
int main()
{
test();
system("pause");
return 0;
}
2、extractObject.cpp
结果
测试代码
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
static int test()
{
// Read input image
std::string path_boldt = "F:/images/boldt.jpg";
cv::Mat image= cv::imread(path_boldt);
if (!image.data)
return 0;
// Display the image
cv::namedWindow("Original Image");
cv::imshow("Original Image",image);
// define bounding rectangle
cv::Rect rectangle(50,25,210,180);
// the models (internally used)
cv::Mat bgModel,fgModel;
// segmentation result
cv::Mat result; // segmentation (4 possible values)
// GrabCut segmentation
cv::grabCut(image, // input image
result, // segmentation result
rectangle,// rectangle containing foreground
bgModel, fgModel, // models
5, // number of iterations
cv::GC_INIT_WITH_RECT); // use rectangle
// Get the pixels marked as likely foreground
cv::compare(result,cv::GC_PR_FGD,result,cv::CMP_EQ);
// or:
// result= result&1;
// create a white image
cv::Mat foreground(image.size(), CV_8UC3,
cv::Scalar(255, 255, 255));
image.copyTo(foreground,result); // bg pixels not copied
// draw rectangle on original image
cv::rectangle(image, rectangle, cv::Scalar(255,255,255),1);
cv::namedWindow("Image with rectangle");
cv::imshow("Image with rectangle",image);
// display result
cv::namedWindow("Foreground object");
cv::imshow("Foreground object",foreground);
cv::waitKey();
return 0;
}
int main()
{
test();
system("pause");
return 0;
}
3、huesaturation.cpp
结果
测试代码
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <vector>
void detectHScolor(const cv::Mat& image, // input image
double minHue, double maxHue, // Hue interval
double minSat, double maxSat, // saturation interval
cv::Mat& mask) { // output mask
// convert into HSV space
cv::Mat hsv;
cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
// split the 3 channels into 3 images
std::vector<cv::Mat> channels;
cv::split(hsv, channels);
// channels[0] is the Hue
// channels[1] is the Saturation
// channels[2] is the Value
// Hue masking
cv::Mat mask1; // below maxHue
cv::threshold(channels[0], mask1, maxHue, 255, cv::THRESH_BINARY_INV);
cv::Mat mask2; // over minHue
cv::threshold(channels[0], mask2, minHue, 255, cv::THRESH_BINARY);
cv::Mat hueMask; // hue mask
if (minHue < maxHue)
hueMask = mask1 & mask2;
else // if interval crosses the zero-degree axis
hueMask = mask1 | mask2;
// Saturation masking
// below maxSat
cv::threshold(channels[1], mask1, maxSat, 255, cv::THRESH_BINARY_INV);
// over minSat
cv::threshold(channels[1], mask2, minSat, 255, cv::THRESH_BINARY);
cv::Mat satMask; // saturation mask
satMask = mask1 & mask2;
// combined mask
mask = hueMask&satMask;
}
static int test()
{
// read the image
std::string path_boldt = "F:/images/boldt.jpg";
cv::Mat image= cv::imread(path_boldt);
if (!image.data)
return 0;
// show original image
cv::namedWindow("Original image");
cv::imshow("Original image",image);
// convert into HSV space
cv::Mat hsv;
cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
// split the 3 channels into 3 images
std::vector<cv::Mat> channels;
cv::split(hsv,channels);
// channels[0] is the Hue
// channels[1] is the Saturation
// channels[2] is the Value
// display value
cv::namedWindow("Value");
cv::imshow("Value",channels[2]);
// display saturation
cv::namedWindow("Saturation");
cv::imshow("Saturation",channels[1]);
// display hue
cv::namedWindow("Hue");
cv::imshow("Hue",channels[0]);
// image with fixed value
cv::Mat newImage;
cv::Mat tmp(channels[2].clone());
// Value channel will be 255 for all pixels
channels[2]= 255;
// merge back the channels
cv::merge(channels,hsv);
// re-convert to BGR
cv::cvtColor(hsv,newImage, cv::COLOR_HSV2BGR);
cv::namedWindow("Fixed Value Image");
cv::imshow("Fixed Value Image",newImage);
// image with fixed saturation
channels[1]= 255;
channels[2]= tmp;
cv::merge(channels,hsv);
cv::cvtColor(hsv,newImage, cv::COLOR_HSV2BGR);
cv::namedWindow("Fixed saturation");
cv::imshow("Fixed saturation",newImage);
// image with fixed value and fixed saturation
channels[1]= 255;
channels[2]= 255;
cv::merge(channels,hsv);
cv::cvtColor(hsv,newImage, cv::COLOR_HSV2BGR);
cv::namedWindow("Fixed saturation/value");
cv::imshow("Fixed saturation/value",newImage);
// artificial image shown the all possible HS colors
cv::Mat hs(128, 360, CV_8UC3);
for (int h = 0; h < 360; h++) {
for (int s = 0; s < 128; s++) {
hs.at<cv::Vec3b>(s, h)[0] = h/2; // all hue angles
hs.at<cv::Vec3b>(s, h)[1] = 255-s*2; // from high saturation to low
hs.at<cv::Vec3b>(s, h)[2] = 255; // constant value
}
}
cv::cvtColor(hs, newImage, cv::COLOR_HSV2BGR);
cv::namedWindow("Hue/Saturation");
cv::imshow("Hue/Saturation", newImage);
// Testing skin detection
// read the image
std::string path_girl = "F:/images/renwu1.jpg";
image= cv::imread(path_girl);
if (!image.data)
return 0;
// show original image
cv::namedWindow("Original image");
cv::imshow("Original image",image);
// detect skin tone
cv::Mat mask;
detectHScolor(image,
160, 10, // hue from 320 degrees to 20 degrees
25, 166, // saturation from ~0.1 to 0.65
mask);
// show masked image
cv::Mat detected(image.size(), CV_8UC3, cv::Scalar(0, 0, 0));
image.copyTo(detected, mask);
cv::imshow("Detection result",detected);
// A test comparing luminance and brightness
// create linear intensity image
cv::Mat linear(100,256,CV_8U);
for (int i=0; i<256; i++) {
linear.col(i)= i;
}
// create a Lab image
linear.copyTo(channels[0]);
cv::Mat constante(100,256,CV_8U,cv::Scalar(128));
constante.copyTo(channels[1]);
constante.copyTo(channels[2]);
cv::merge(channels,image);
// convert back to BGR
cv::Mat brightness;
cv::cvtColor(image,brightness, cv::COLOR_Lab2BGR);
cv::split(brightness, channels);
// create combined image
cv::Mat combined(200,256, CV_8U);
cv::Mat half1(combined,cv::Rect(0,0,256,100));
linear.copyTo(half1);
cv::Mat half2(combined,cv::Rect(0,100,256,100));
channels[0].copyTo(half2);
cv::namedWindow("Luminance vs Brightness");
cv::imshow("Luminance vs Brightness",combined);
cv::waitKey();
}
int main()
{
test();
system("pause");
return 0;
}
Chapter04
1、contentFinder.cpp
结果
测试代码
#include <iostream>
using namespace std;
#include<opencv2/opencv.hpp>
#include "histogram.h"
#include "contentFinder.h"
#include "colorhistogram.h"
static int test()
{
// Read input image
std::string path_waves = "F:/images/waves.jpg";
cv::Mat image = cv::imread(path_waves, 0);
if (!image.data)
return 0;
// define image ROI
cv::Mat imageROI;
imageROI = image(cv::Rect(216, 33, 24, 30)); // Cloud region
// Display reference patch
cv::namedWindow("Reference");
cv::imshow("Reference", imageROI);
// Find histogram of reference
Histogram1D h;
cv::Mat hist = h.getHistogram(imageROI);
cv::namedWindow("Reference Hist");
cv::imshow("Reference Hist", h.getHistogramImage(imageROI));
// Create the content finder
ContentFinder finder;
// set histogram to be back-projected
finder.setHistogram(hist);
finder.setThreshold(-1.0f);
// Get back-projection
cv::Mat result1;
result1 = finder.find(image);
// Create negative image and display result
cv::Mat tmp;
result1.convertTo(tmp, CV_8U, -1.0, 255.0);
cv::namedWindow("Backprojection result");
cv::imshow("Backprojection result", tmp);
// Get binary back-projection
finder.setThreshold(0.12f);
result1 = finder.find(image);
// Draw a rectangle around the reference area
cv::rectangle(image, cv::Rect(216, 33, 24, 30), cv::Scalar(0, 0, 0));
// Display image
cv::namedWindow("Image");
cv::imshow("Image", image);
// Display result
cv::namedWindow("Detection Result");
cv::imshow("Detection Result", result1);
// Load color image
ColorHistogram hc;
cv::Mat color = cv::imread(path_waves);
// extract region of interest
imageROI = color(cv::Rect(0, 0, 100, 45)); // blue sky area
// Get 3D colour histogram (8 bins per channel)
hc.setSize(8); // 8x8x8
cv::Mat shist = hc.getHistogram(imageROI);
// set histogram to be back-projected
finder.setHistogram(shist);
finder.setThreshold(0.05f);
// Get back-projection of color histogram
result1 = finder.find(color);
cv::namedWindow("Color Detection Result");
cv::imshow("Color Detection Result", result1);
// Second color image
std::string path_dog = "F:/images/dog.jpg";
cv::Mat color2 = cv::imread(path_dog);
cv::namedWindow("Second Image");
cv::imshow("Second Image", color2);
// Get back-projection of color histogram
cv::Mat result2 = finder.find(color2);
cv::namedWindow("Result color (2)");
cv::imshow("Result color (2)", result2);
// Get ab color histogram
hc.setSize(256); // 256x256
cv::Mat colorhist = hc.getabHistogram(imageROI);
// display 2D histogram
colorhist.convertTo(tmp, CV_8U, -1.0, 255.0);
cv::namedWindow("ab histogram");
cv::imshow("ab histogram", tmp);
// set histogram to be back-projected
finder.setHistogram(colorhist);
finder.setThreshold(0.05f);
// Convert to Lab space
cv::Mat lab;
cv::cvtColor(color, lab, cv::COLOR_BGR2Lab);
// Get back-projection of ab histogram
int ch[2] = { 1,2 };
result1 = finder.find(lab, 0, 256.0f, ch);
cv::namedWindow("Result ab (1)");
cv::imshow("Result ab (1)", result1);
// Second colour image
cv::cvtColor(color2, lab, cv::COLOR_BGR2Lab);
// Get back-projection of ab histogram
result2 = finder.find(lab, 0, 256.0, ch);
cv::namedWindow("Result ab (2)");
cv::imshow("Result ab (2)", result2);
// Draw a rectangle around the reference sky area
cv::rectangle(color, cv::Rect(0, 0, 100, 45), cv::Scalar(0, 0, 0));
cv::namedWindow("Color Image");
cv::imshow("Color Image", color);
// Get Hue colour histogram
hc.setSize(180); // 180 bins
colorhist = hc.getHueHistogram(imageROI);
// set histogram to be back-projected
finder.setHistogram(colorhist);
// Convert to HSV space
cv::Mat hsv;
cv::cvtColor(color, hsv, cv::COLOR_BGR2HSV);
// Get back-projection of hue histogram
ch[0] = 0;
result1 = finder.find(hsv, 0.0f, 180.0f, ch);
cv::namedWindow("Result Hue (1)");
cv::imshow("Result Hue (1)", result1);
// Second colour image
color2 = cv::imread(path_dog);
// Convert to HSV space
cv::cvtColor(color2, hsv, cv::COLOR_BGR2HSV);
// Get back-projection of hue histogram
result2 = finder.find(hsv, 0.0f, 180.0f, ch);
cv::namedWindow("Result Hue (2)");
cv::imshow("Result Hue (2)", result2);
cv::waitKey();
return 0;
}
int main()
{
test();
system("pause");
return 0;
}
histogram.h
#if !defined HISTOGRAM
#define HISTOGRAM
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
// To create histograms of gray-level images
class Histogram1D {
private:
int histSize[1]; // number of bins in histogram
float hranges[2]; // range of values
const float* ranges[1]; // pointer to the different value ranges
int channels[1]; // channel number to be examined
public:
Histogram1D() {
// Prepare default arguments for 1D histogram
histSize[0]= 256; // 256 bins
hranges[0]= 0.0; // from 0 (inclusive)
hranges[1]= 256.0; // to 256 (exclusive)
ranges[0]= hranges;
channels[0]= 0; // we look at channel 0
}
// Sets the channel on which histogram will be calculated.
// By default it is channel 0.
void setChannel(int c) {
channels[0]= c;
}
// Gets the channel used.
int getChannel() {
return channels[0];
}
// Sets the range for the pixel values.
// By default it is [0,256[
void setRange(float minValue, float maxValue) {
hranges[0]= minValue;
hranges[1]= maxValue;
}
// Gets the min pixel value.
float getMinValue() {
return hranges[0];
}
// Gets the max pixel value.
float getMaxValue() {
return hranges[1];
}
// Sets the number of bins in histogram.
// By default it is 256.
void setNBins(int nbins) {
histSize[0]= nbins;
}
// Gets the number of bins in histogram.
int getNBins() {
return histSize[0];
}
// Computes the 1D histogram.
cv::Mat getHistogram(const cv::Mat &image) {
cv::Mat hist;
// Compute 1D histogram with calcHist
cv::calcHist(&image,
1, // histogram of 1 image only
channels, // the channel used
cv::Mat(), // no mask is used
hist, // the resulting histogram
1, // it is a 1D histogram
histSize, // number of bins
ranges // pixel value range
);
return hist;
}
// Computes the 1D histogram and returns an image of it.
cv::Mat getHistogramImage(const cv::Mat &image, int zoom = 1){
// Compute histogram first
cv::Mat hist = getHistogram(image);
// Creates image
return Histogram1D::getImageOfHistogram(hist, zoom);
}
// Stretches the source image using min number of count in bins.
cv::Mat stretch(const cv::Mat &image, int minValue = 0) {
// Compute histogram first
cv::Mat hist = getHistogram(image);
// find left extremity of the histogram
int imin = 0;
for (; imin < histSize[0]; imin++) {
// ignore bins with less than minValue entries
if (hist.at<float>(imin) > minValue)
break;
}
// find right extremity of the histogram
int imax = histSize[0] - 1;
for (; imax >= 0; imax--) {
// ignore bins with less than minValue entries
if (hist.at<float>(imax) > minValue)
break;
}
// Create lookup table
int dims[1] = { 256 };
cv::Mat lookup(1, dims, CV_8U);
for (int i = 0; i<256; i++) {
if (i < imin) lookup.at<uchar>(i) = 0;
else if (i > imax) lookup.at<uchar>(i) = 255;
else lookup.at<uchar>(i) = cvRound(255.0*(i - imin) / (imax - imin));
}
// Apply lookup table
cv::Mat result;
result = applyLookUp(image, lookup);
return result;
}
// Stretches the source image using percentile.
cv::Mat stretch(const cv::Mat &image, float percentile) {
// number of pixels in percentile
float number= image.total()*percentile;
// Compute histogram first
cv::Mat hist = getHistogram(image);
// find left extremity of the histogram
int imin = 0;
for (float count=0.0; imin < 256; imin++) {
// number of pixel at imin and below must be > number
if ((count+=hist.at<float>(imin)) >= number)
break;
}
// find right extremity of the histogram
int imax = 255;
for (float count=0.0; imax >= 0; imax--) {
// number of pixel at imax and below must be > number
if ((count += hist.at<float>(imax)) >= number)
break;
}
// Create lookup table
int dims[1] = { 256 };
cv::Mat lookup(1, dims, CV_8U);
for (int i = 0; i<256; i++) {
if (i < imin) lookup.at<uchar>(i) = 0;
else if (i > imax) lookup.at<uchar>(i) = 255;
else lookup.at<uchar>(i) = cvRound(255.0*(i - imin) / (imax - imin));
}
// Apply lookup table
cv::Mat result;
result = applyLookUp(image, lookup);
return result;
}
// static methods
// Create an image representing a histogram
static cv::Mat getImageOfHistogram(const cv::Mat &hist, int zoom) {
// Get min and max bin values
double maxVal = 0;
double minVal = 0;
cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);
// get histogram size
int histSize = hist.rows;
// Square image on which to display histogram
cv::Mat histImg(histSize*zoom, histSize*zoom, CV_8U, cv::Scalar(255));
// set highest point at 90% of nbins (i.e. image height)
int hpt = static_cast<int>(0.9*histSize);
// Draw vertical line for each bin
for (int h = 0; h < histSize; h++) {
float binVal = hist.at<float>(h);
if (binVal>0) {
int intensity = static_cast<int>(binVal*hpt / maxVal);
cv::line(histImg, cv::Point(h*zoom, histSize*zoom),
cv::Point(h*zoom, (histSize - intensity)*zoom), cv::Scalar(0), zoom);
}
}
return histImg;
}
// Equalizes the source image.
static cv::Mat equalize(const cv::Mat &image) {
cv::Mat result;
cv::equalizeHist(image,result);
return result;
}
// Applies a lookup table transforming an input image into a 1-channel image
static cv::Mat applyLookUp(const cv::Mat& image, // input image
const cv::Mat& lookup) { // 1x256 uchar matrix
// the output image
cv::Mat result;
// apply lookup table
cv::LUT(image,lookup,result);
return result;
}
// Applies a lookup table transforming an input image into a 1-channel image
// this is a test version with iterator; always use function cv::LUT
static cv::Mat applyLookUpWithIterator(const cv::Mat& image, const cv::Mat& lookup) {
// Set output image (always 1-channel)
cv::Mat result(image.rows,image.cols,CV_8U);
cv::Mat_<uchar>::iterator itr= result.begin<uchar>();
// Iterates over the input image
cv::Mat_<uchar>::const_iterator it= image.begin<uchar>();
cv::Mat_<uchar>::const_iterator itend= image.end<uchar>();
// Applies lookup to each pixel
for ( ; it!= itend; ++it, ++itr) {
*itr= lookup.at<uchar>(*it);
}
return result;
}
};
#endif
contentFinder.h
#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;
}
// 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);
}
// Simplified version in which
// 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];
cv::calcBackProject(&image,
1, // we only use one image at a time
channels, // vector specifying what histogram dimensions belong to what image channels
histogram, // 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
);
}
// Threshold back projection to obtain a binary image
if (threshold > 0.0)
cv::threshold(result, result, 255.0*threshold, 255.0, cv::THRESH_BINARY);
return result;
}
};
#endif
colorhistogram.h
#if !defined COLHISTOGRAM
#define COLHISTOGRAM
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
class ColorHistogram {
private:
int histSize[3]; // size of each dimension
float hranges[2]; // range of values (same for the 3 dimensions)
const float* ranges[3]; // array of ranges for each dimension
int channels[3]; // channel to be considered
public:
ColorHistogram() {
// Prepare default arguments for a color histogram
// each dimension has equal size and range
histSize[0] = histSize[1] = histSize[2] = 256;
hranges[0] = 0.0; // BRG range from 0 to 256
hranges[1] = 256.0;
ranges[0] = hranges; // in this class,
ranges[1] = hranges; // all channels have the same range
ranges[2] = hranges;
channels[0] = 0; // the three channels: B
channels[1] = 1; // G
channels[2] = 2; // R
}
// set histogram size for each dimension
void setSize(int size) {
// each dimension has equal size
histSize[0] = histSize[1] = histSize[2] = size;
}
// Computes the histogram.
cv::Mat getHistogram(const cv::Mat &image) {
cv::Mat hist;
// BGR color histogram
hranges[0] = 0.0; // BRG range
hranges[1] = 256.0;
channels[0] = 0; // the three channels
channels[1] = 1;
channels[2] = 2;
// Compute histogram
cv::calcHist(&image,
1, // histogram of 1 image only
channels, // the channel used
cv::Mat(), // no mask is used
hist, // the resulting histogram
3, // it is a 3D histogram
histSize, // number of bins
ranges // pixel value range
);
return hist;
}
// Computes the histogram.
cv::SparseMat getSparseHistogram(const cv::Mat &image) {
cv::SparseMat hist(3, // number of dimensions
histSize, // size of each dimension
CV_32F);
// BGR color histogram
hranges[0] = 0.0; // BRG range
hranges[1] = 256.0;
channels[0] = 0; // the three channels
channels[1] = 1;
channels[2] = 2;
// Compute histogram
cv::calcHist(&image,
1, // histogram of 1 image only
channels, // the channel used
cv::Mat(), // no mask is used
hist, // the resulting histogram
3, // it is a 3D histogram
histSize, // number of bins
ranges // pixel value range
);
return hist;
}
// Computes the 1D Hue histogram.
// BGR source image is converted to HSV
// Pixels with low saturation are ignored
cv::Mat getHueHistogram(const cv::Mat &image,
int minSaturation = 0) {
cv::Mat hist;
// Convert to HSV colour space
cv::Mat hsv;
cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
// Mask to be used (or not)
cv::Mat mask;
// creating the mask if required
if (minSaturation > 0) {
// Spliting the 3 channels into 3 images
std::vector<cv::Mat> v;
cv::split(hsv, v);
// Mask out the low saturated pixels
cv::threshold(v[1], mask, minSaturation, 255,
cv::THRESH_BINARY);
}
// Prepare arguments for a 1D hue histogram
hranges[0] = 0.0; // range is from 0 to 180
hranges[1] = 180.0;
channels[0] = 0; // the hue channel
// Compute histogram
cv::calcHist(&hsv,
1, // histogram of 1 image only
channels, // the channel used
mask, // binary mask
hist, // the resulting histogram
1, // it is a 1D histogram
histSize, // number of bins
ranges // pixel value range
);
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::COLOR_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
2、finder.cpp
结果
测试代码
#include <iostream>
#include <vector>
using namespace std;
#include<opencv2/opencv.hpp>
#include "contentFinder.h"
#include "colorhistogram.h"
static int test()
{
// Read reference image
std::string path_baboon01 = "F:/images/baboon01.jpg";
cv::Mat image = cv::imread(path_baboon01);
if (!image.data)
return 0;
// initial window position
cv::Rect rect(110, 45, 35, 45);
cv::rectangle(image, rect, cv::Scalar(0, 0, 255));
// Baboon's face ROI
cv::Mat imageROI = image(rect);
cv::namedWindow("Image 1");
cv::imshow("Image 1", image);
// Get the Hue histogram of the Baboon's face
int minSat = 65;
ColorHistogram hc;
cv::Mat colorhist = hc.getHueHistogram(imageROI, minSat);
ContentFinder finder;
finder.setHistogram(colorhist);
finder.setThreshold(0.2f);
// Convert to HSV space (just for display)
cv::Mat hsv;
cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
// Split the image
vector<cv::Mat> v;
cv::split(hsv, v);
// Eliminate pixels with low saturation
cv::threshold(v[1], v[1], minSat, 255, cv::THRESH_BINARY);
cv::namedWindow("Saturation mask");
cv::imshow("Saturation mask", v[1]);
//--------------
// Second image
std::string path_baboon02 = "F:/images/baboon02.jpg";
image = cv::imread(path_baboon02);
cv::namedWindow("Image 2");
cv::imshow("Image 2", image);
// Convert to HSV space
cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
// Get back-projection of hue histogram
int ch[1] = { 0 };
finder.setThreshold(-1.0f); // no thresholding
cv::Mat result = finder.find(hsv, 0.0f, 180.0f, ch);
// Display back projection result
cv::namedWindow("Backprojection on second image");
cv::imshow("Backprojection on second image", result);
// initial window position
cv::rectangle(image, rect, cv::Scalar(0, 0, 255));
// search objet with mean shift
cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER | cv::TermCriteria::EPS,
10, // iterate max 10 times
1); // or until the change in centroid position is less than 1px
cout << "meanshift= " << cv::meanShift(result, rect, criteria) << endl;
// draw output window
cv::rectangle(image, rect, cv::Scalar(0, 255, 0));
// Display image
cv::namedWindow("Image 2 result");
cv::imshow("Image 2 result", image);
cv::waitKey();
return 0;
}
int main()
{
test();
system("pause");
return 0;
}
#include "contentFinder.h"头文件
#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;
}
// 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);
}
// Simplified version in which
// 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];
cv::calcBackProject(&image,
1, // we only use one image at a time
channels, // vector specifying what histogram dimensions belong to what image channels
histogram, // 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
);
}
// Threshold back projection to obtain a binary image
if (threshold > 0.0)
cv::threshold(result, result, 255.0*threshold, 255.0, cv::THRESH_BINARY);
return result;
}
};
#endif
#include "colorhistogram.h"头文件
#if !defined COLHISTOGRAM
#define COLHISTOGRAM
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
class ColorHistogram {
private:
int histSize[3]; // size of each dimension
float hranges[2]; // range of values (same for the 3 dimensions)
const float* ranges[3]; // array of ranges for each dimension
int channels[3]; // channel to be considered
public:
ColorHistogram() {
// Prepare default arguments for a color histogram
// each dimension has equal size and range
histSize[0] = histSize[1] = histSize[2] = 256;
hranges[0] = 0.0; // BRG range from 0 to 256
hranges[1] = 256.0;
ranges[0] = hranges; // in this class,
ranges[1] = hranges; // all channels have the same range
ranges[2] = hranges;
channels[0] = 0; // the three channels: B
channels[1] = 1; // G
channels[2] = 2; // R
}
// set histogram size for each dimension
void setSize(int size) {
// each dimension has equal size
histSize[0] = histSize[1] = histSize[2] = size;
}
// Computes the histogram.
cv::Mat getHistogram(const cv::Mat &image) {
cv::Mat hist;
// BGR color histogram
hranges[0] = 0.0; // BRG range
hranges[1] = 256.0;
channels[0] = 0; // the three channels
channels[1] = 1;
channels[2] = 2;
// Compute histogram
cv::calcHist(&image,
1, // histogram of 1 image only
channels, // the channel used
cv::Mat(), // no mask is used
hist, // the resulting histogram
3, // it is a 3D histogram
histSize, // number of bins
ranges // pixel value range
);
return hist;
}
// Computes the histogram.
cv::SparseMat getSparseHistogram(const cv::Mat &image) {
cv::SparseMat hist(3, // number of dimensions
histSize, // size of each dimension
CV_32F);
// BGR color histogram
hranges[0] = 0.0; // BRG range
hranges[1] = 256.0;
channels[0] = 0; // the three channels
channels[1] = 1;
channels[2] = 2;
// Compute histogram
cv::calcHist(&image,
1, // histogram of 1 image only
channels, // the channel used
cv::Mat(), // no mask is used
hist, // the resulting histogram
3, // it is a 3D histogram
histSize, // number of bins
ranges // pixel value range
);
return hist;
}
// Computes the 1D Hue histogram.
// BGR source image is converted to HSV
// Pixels with low saturation are ignored
cv::Mat getHueHistogram(const cv::Mat &image,
int minSaturation = 0) {
cv::Mat hist;
// Convert to HSV colour space
cv::Mat hsv;
cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
// Mask to be used (or not)
cv::Mat mask;
// creating the mask if required
if (minSaturation > 0) {
// Spliting the 3 channels into 3 images
std::vector<cv::Mat> v;
cv::split(hsv, v);
// Mask out the low saturated pixels
cv::threshold(v[1], mask, minSaturation, 255,
cv::THRESH_BINARY);
}
// Prepare arguments for a 1D hue histogram
hranges[0] = 0.0; // range is from 0 to 180
hranges[1] = 180.0;
channels[0] = 0; // the hue channel
// Compute histogram
cv::calcHist(&hsv,
1, // histogram of 1 image only
channels, // the channel used
mask, // binary mask
hist, // the resulting histogram
1, // it is a 1D histogram
histSize, // number of bins
ranges // pixel value range
);
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::COLOR_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