AHTcode
De Pontão Nós Digitais
Ir para navegaçãoIr para pesquisar
Aí está o código, na íntegra
Em Breve: More comments!
/*
Programa esqueleto da AirHackTable
*/
#include "opencv/highgui.h"
#include "opencv/cv.h"
#include <stdio.h>
using namespace cv;
void pausef(void);
class ColorHistogram
{
private:
int histSize[3];
float hranges[2];
const float* ranges[3];
int channels[3];
public:
ColorHistogram()
{
// Prepare arguments for a color histogram
histSize[0]= histSize[1]= histSize[2]= 256;
hranges[0]= 0.0; // BRG range
hranges[1]= 255.0;
ranges[0]= hranges; // all channels have the same range
ranges[1]= hranges;
ranges[2]= hranges;
channels[0]= 0; // the three channels
channels[1]= 1;
channels[2]= 2;
}
cv::MatND getHistogram(const cv::Mat &image)
{
cv::MatND hist;
// 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 with a mask.
// BGR source image is converted to HSV
// Pixels with low saturation are ignored
cv::MatND getHueHistogram(const cv::Mat &image,
int minSaturation=0)
{
cv::MatND hist;
// Convert to HSV color space
cv::Mat hsv;
cv::cvtColor(image, hsv, CV_BGR2HSV);
// Mask to be used (or not)
cv::Mat mask;
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;
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;
}
};
class ContentFinder
{
private:
float hranges[2];
const float* ranges[3];
int channels[3];
float threshold;
cv::MatND histogram;
public:
ContentFinder() : threshold(-1.0f)
{
ranges[0]= hranges; // all channels have same range
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 MatND& h)
{
histogram= h;
cv::normalize(histogram,histogram,1.0);
}
Mat find(const cv::Mat& image)
{
Mat result;
hranges[0]= 0.0; // range [0,255]
hranges[1]= 255.0;
channels[0]= 0; // the three channels
channels[1]= 1;
channels[2]= 2;
cv::calcBackProject(&image,
1, // one image
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*threshold, 255, cv::THRESH_BINARY);
return result;
}
Mat 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];
// NOT USING THIS PART
// if (isSparse) { // call the right function based on histogram type
//
// 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 {
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*threshold, 255, cv::THRESH_BINARY);
return result;
}
};
// AirHackTable
class AHT
{
private:
// int pad;
#define TAM 1
#define PAD 15
// amount of circles to be detected
ContentFinder circleFinder;
ColorHistogram hist;
Point circleCenter;
Point circleCenter2;
void sharpen(Mat &image)
{
// Construct kernel (all entries initialized to 0)
Mat kernel(3,3,CV_32F,Scalar(0));
// assigns kernel values
kernel.at<float>(1,1)= 5.0;
kernel.at<float>(0,1)= -1.0;
kernel.at<float>(2,1)= -1.0;
kernel.at<float>(1,0)= -1.0;
kernel.at<float>(1,2)= -1.0;
// filter the image
filter2D( image, image, image.depth(), kernel);
}
void colorReduce(Mat &image, int div=64)
{
int nl = image.rows; // number of lines
// total number of elements per line
int nc = image.cols * image.channels();
for (int j = 0; j < nl; j++)
{
// get the address of row j
uchar* data = image.ptr<uchar>(j);
for (int i = 0; i < nc; i++)
{
data[i] = data[i]/div*div + div/2;
} // end of line
}
}
public:
Mat process(Mat &image)
{
Mat result, thres;
flip( image, image, 1 );
sharpen( image );
colorReduce( image, 32 );
cvtColor( image, result, CV_RGB2GRAY );
equalizeHist( result, result );
// Canny( result, result, 0, 255);
GaussianBlur( result, result, Size(7,7) , 3);
// threshold( result, thres, 110, 255, CV_THRESH_BINARY);
// result += thres/10;
return result;
}
// old version, not using anymore
// it is still here so I can use its code
void findCircles(Mat &image, Mat result, int minSaturation=0)
{
circleFinder.setThreshold(0.05f);
// pad = 15;
double count, sx[TAM] = { 0 }, sy[TAM] = { 0 };
// holds the detected circles
vector<Vec3f> circles;
HoughCircles( result( Rect( PAD, PAD, result.cols-PAD, result.rows-PAD) ), circles, CV_HOUGH_GRADIENT, 1.65, 32);
// TODO
// To be improved
for( size_t i = 0, count = 0; i < circles.size() && count < TAM; i++, count++ )
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
// if ( (center.x - sx[count] < 5) && ( center.y - sy[count] < 5) )
{
Mat ROI = image( Rect( center.x-PAD, center.y-PAD, 2*PAD, 2*PAD ) );
circleFinder.setHistogram(hist.getHueHistogram(ROI, minSaturation));
// hist = f.find(image);
// hist += f.find(image);
circle( image, Point(center.x+PAD, center.y+PAD) , 19, 255, 2 );
}
sx[count] = center.x;
sy[count] = center.y;
}
}
void getCircles(Mat image, Mat result, int minSaturation=0)
{
// holds the detected circles
vector<Vec3f> circles;
HoughCircles( result( Rect( PAD, PAD, result.cols-PAD, result.rows-PAD) ), circles, CV_HOUGH_GRADIENT, 1.65, 32);
// TODO
if( circles.size() )
{
Point center(cvRound(circles[0][0]), cvRound(circles[0][1]));
Mat ROI = image( Rect( center.x-PAD, center.y-PAD, 2*PAD, 2*PAD ) );
circleFinder.setHistogram(hist.getHueHistogram(ROI, minSaturation));
circleCenter = center;
}
}
// not using yet
void nextPosition(Mat image, int minSaturation=0)
{
Mat hsv;
// Convert to HSV space
cvtColor( image, hsv, CV_BGR2HSV );
std::vector<Mat> v;
// Split the image
split( hsv, v );
// Identify pixels with low saturation
threshold( v[1], v[1], minSaturation, 255, THRESH_BINARY );
int ch[1]={0};
// Get back-projection of hue histogram
Mat result = circleFinder.find( hsv, 0.0f, 180.0f, ch,1 );
// Eliminate low stauration pixels
bitwise_and( result, v[1], result );
Rect rect(circleCenter.x+PAD,circleCenter.y+PAD,1,1);
// rectangle(image, rect, cv::Scalar(0,0,255));
TermCriteria criteria( cv::TermCriteria::MAX_ITER, 10, 0.01 );
meanShift( result, rect, criteria );
circleCenter2.x = rect.x;
circleCenter2.y = rect.y;
// return result;
}
void drawCircle(Mat &image)
{
if( circleCenter.x != 0 )
circle( image, Point(circleCenter.x+PAD, circleCenter.y+PAD) , 19, 255, 2 );
if( circleCenter2.x != 0 )
circle( image, Point(circleCenter2.x, circleCenter2.y) , 19, 0, 2 );
}
};
int main( int argc, char** argv )
{
char c;
int minSat = 65;
namedWindow( "player", 0 );
// namedWindow( "mod", 0 );
// namedWindow( "Histogram", 0 );
CvCapture *cam;
if( argc != 2 )
cam = cvCreateCameraCapture(0);
// else
// cam.open( string(argv[1]) )
Mat frame, modframe;
AHT image;
while(1)
{
// gets the next frame
frame = cvQueryFrame(cam);
if(!frame.data) break;
modframe = image.process(frame);
// look for the circles
// image.findCircles(frame, modframe);
if( c == 'g' )
image.getCircles(frame, modframe, minSat);
if( c == 'n' )
image.nextPosition(frame, minSat);
image.drawCircle(frame);
// show results
// imshow("Histogram", hist);
imshow( "player", frame );
// imshow( "mod", modframe );
c = cvWaitKey(3);
// c == ESC
if( c == 27 ) break;
else if( c == ' ' || c == 'p' ) pausef();
}
destroyWindow("player");
// destroyWindow("mod");
// destroyWindow("Histogram");
return 0;
}
void pausef()
{
char c = 0;
while( c != 'p' && c != ' ' )
c = cvWaitKey(0);
}
Pode comentar, se precisar de me contatar veja meus contatos aqui