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