Subversion Repositories OpenCV2-Cookbook

Rev

View as "text/plain" | Blame | Last modification | View Log | RSS feed

1
/*------------------------------------------------------------------------------------------*\
   This file contains material supporting chapter 7 of the cookbook:  
   Computer Vision Programming using the OpenCV Library.
   by Robert Laganiere, Packt Publishing, 2011.

   This program is free software; permission is hereby granted to use, copy, modify,
   and distribute this source code, or portions thereof, for any purpose, without fee,
   subject to the restriction that the copyright notice may not be removed
   or altered from any source or altered source distribution.
   The software is released on an as-is basis and without any warranties of any kind.
   In particular, the software is not guaranteed to be fault-tolerant or free from failure.
   The author disclaims all warranties with regard to this software, any use,
   and any consequent failure, is purely the responsibility of the user.
 
   Copyright (C) 2010-2011 Robert Laganiere, www.laganiere.name
\*------------------------------------------------------------------------------------------*/


#include <iostream>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

#include "linefinder.h"
#include "edgedetector.h"

#define PI 3.1415926

int main()
{
        // Read input image
        cv::Mat image= cv::imread("../road.jpg",0);
        if (!image.data)
                return 0;

    // Display the image
        cv::namedWindow("Original Image");
        cv::imshow("Original Image",image);

        // Compute Sobel
        EdgeDetector ed;
        ed.computeSobel(image);

    // Display the Sobel orientation
        cv::namedWindow("Sobel (orientation)");
        cv::imshow("Sobel (orientation)",ed.getSobelOrientationImage());
        cv::imwrite("ori.bmp",ed.getSobelOrientationImage());

    // Display the Sobel low threshold
        cv::namedWindow("Sobel (low threshold)");
        cv::imshow("Sobel (low threshold)",ed.getBinaryMap(125));

    // Display the Sobel high threshold
        cv::namedWindow("Sobel (high threshold)");
        cv::imshow("Sobel (high threshold)",ed.getBinaryMap(350));

        // Apply Canny algorithm
        cv::Mat contours;
        cv::Canny(image,contours,125,350);
        cv::Mat contoursInv;
        cv::threshold(contours,contoursInv,128,255,cv::THRESH_BINARY_INV);

    // Display the image of contours
        cv::namedWindow("Canny Contours");
        cv::imshow("Canny Contours",contoursInv);

        // Create a test image
        cv::Mat test(200,200,CV_8U,cv::Scalar(0));
        cv::line(test,cv::Point(100,0),cv::Point(200,200),cv::Scalar(255));
        cv::line(test,cv::Point(0,50),cv::Point(200,200),cv::Scalar(255));
        cv::line(test,cv::Point(0,200),cv::Point(200,0),cv::Scalar(255));
        cv::line(test,cv::Point(200,0),cv::Point(0,200),cv::Scalar(255));
        cv::line(test,cv::Point(100,0),cv::Point(100,200),cv::Scalar(255));
        cv::line(test,cv::Point(0,100),cv::Point(200,100),cv::Scalar(255));

    // Display the test image
        cv::namedWindow("Test Image");
        cv::imshow("Test Image",test);
        cv::imwrite("test.bmp",test);

        // Hough tranform for line detection
        std::vector<cv::Vec2f> lines;
        cv::HoughLines(contours,lines,1,PI/180,60);

        // Draw the lines
        cv::Mat result(contours.rows,contours.cols,CV_8U,cv::Scalar(255));
        image.copyTo(result);

        std::cout << "Lines detected: " << lines.size() << std::endl;

        std::vector<cv::Vec2f>::const_iterator it= lines.begin();
        while (it!=lines.end()) {

                float rho= (*it)[0];   // first element is distance rho
                float theta= (*it)[1]; // second element is angle theta
               
                if (theta < PI/4. || theta > 3.*PI/4.) { // ~vertical line
               
                        // point of intersection of the line with first row
                        cv::Point pt1(rho/cos(theta),0);        
                        // point of intersection of the line with last row
                        cv::Point pt2((rho-result.rows*sin(theta))/cos(theta),result.rows);
                        // draw a white line
                        cv::line( result, pt1, pt2, cv::Scalar(255), 1);

                } else { // ~horizontal line

                        // point of intersection of the line with first column
                        cv::Point pt1(0,rho/sin(theta));        
                        // point of intersection of the line with last column
                        cv::Point pt2(result.cols,(rho-result.cols*cos(theta))/sin(theta));
                        // draw a white line
                        cv::line( result, pt1, pt2, cv::Scalar(255), 1);
                }

                std::cout << "line: (" << rho << "," << theta << ")\n";

                ++it;
        }

    // Display the detected line image
        cv::namedWindow("Detected Lines with Hough");
        cv::imshow("Detected Lines with Hough",result);

        // Create LineFinder instance
        LineFinder ld;

        // Set probabilistic Hough parameters
        ld.setLineLengthAndGap(100,20);
        ld.setMinVote(80);

        // Detect lines
        std::vector<cv::Vec4i> li= ld.findLines(contours);
        ld.drawDetectedLines(image);
        cv::namedWindow("Detected Lines with HoughP");
        cv::imshow("Detected Lines with HoughP",image);

        std::vector<cv::Vec4i>::const_iterator it2= li.begin();
        while (it2!=li.end()) {

                std::cout << "(" << (*it2)[0] << ","<< (*it2)[1]<< ")-("
                             << (*it2)[2]<< "," << (*it2)[3] << ")" <<std::endl;

                ++it2;
        }

        // Display one line
        image= cv::imread("../road.jpg",0);
        int n=0;
        cv::line(image, cv::Point(li[n][0],li[n][1]),cv::Point(li[n][2],li[n][3]),cv::Scalar(255),5);
        cv::namedWindow("One line of the Image");
        cv::imshow("One line of the Image",image);

        // Extract the contour pixels of the first detected line
        cv::Mat oneline(image.size(),CV_8U,cv::Scalar(0));
        cv::line(oneline, cv::Point(li[n][0],li[n][1]),cv::Point(li[n][2],li[n][3]),cv::Scalar(255),5);
        cv::bitwise_and(contours,oneline,oneline);
        cv::Mat onelineInv;
        cv::threshold(oneline,onelineInv,128,255,cv::THRESH_BINARY_INV);
        cv::namedWindow("One line");
        cv::imshow("One line",onelineInv);

        std::vector<cv::Point> points;

        // Iterate over the pixels to obtain all point positions
        for( int y = 0; y < oneline.rows; y++ ) {
   
                uchar* rowPtr = oneline.ptr<uchar>(y);
   
                for( int x = 0; x < oneline.cols; x++ ) {

                    // if on a contour
                        if (rowPtr[x]) {

                                points.push_back(cv::Point(x,y));
                        }
                }
    }
       
        // find the best fitting line
        cv::Vec4f line;
        cv::fitLine(cv::Mat(points),line,CV_DIST_L2,0,0.01,0.01);

        std::cout << "line: (" << line[0] << "," << line[1] << ")(" << line[2] << "," << line[3] << ")\n";

        int x0= line[2];
        int y0= line[3];
        int x1= x0-200*line[0];
        int y1= y0-200*line[1];
        image= cv::imread("../road.jpg",0);
        cv::line(image,cv::Point(x0,y0),cv::Point(x1,y1),cv::Scalar(0),3);
        cv::namedWindow("Estimated line");
        cv::imshow("Estimated line",image);

        // eliminate inconsistent lines
        ld.removeLinesOfInconsistentOrientations(ed.getOrientation(),0.4,0.1);

   // Display the detected line image
        image= cv::imread("../road.jpg",0);
        ld.drawDetectedLines(image);
        cv::namedWindow("Detected Lines (2)");
        cv::imshow("Detected Lines (2)",image);

        // Create a Hough accumulator
        cv::Mat acc(200,180,CV_8U,cv::Scalar(0));

        // Choose a point
        int x=50, y=30;

        // loop over all angles
        for (int i=0; i<180; i++) {

                double theta= i*PI/180.;

                // find corresponding rho value
                double rho= x*cos(theta)+y*sin(theta);
                int j= static_cast<int>(rho+100.5);

                std::cout << i << "," << j << std::endl;

                // increment accumulator
                acc.at<uchar>(j,i)++;
        }

        cv::imwrite("hough1.bmp",acc*100);

        // Choose a second point
        x=30, y=10;

        // loop over all angles
        for (int i=0; i<180; i++) {

                double theta= i*PI/180.;
                double rho= x*cos(theta)+y*sin(theta);
                int j= static_cast<int>(rho+100.5);

                acc.at<uchar>(j,i)++;
        }

        cv::namedWindow("Hough Accumulator");
        cv::imshow("Hough Accumulator",acc*100);
        cv::imwrite("hough2.bmp",acc*100);

        // Detect circles
        image= cv::imread("../chariot.jpg",0);
        cv::GaussianBlur(image,image,cv::Size(5,5),1.5);
        std::vector<cv::Vec3f> circles;
        cv::HoughCircles(image, circles, CV_HOUGH_GRADIENT,
                2,   // accumulator resolution (size of the image / 2)
                50,  // minimum distance between two circles
                200, // Canny high threshold
                100, // minimum number of votes
                25, 100); // min and max radius

        std::cout << "Circles: " << circles.size() << std::endl;
       
        // Draw the circles
        image= cv::imread("../chariot.jpg",0);
        std::vector<cv::Vec3f>::const_iterator itc= circles.begin();
       
        while (itc!=circles.end()) {
               
          cv::circle(image,
                  cv::Point((*itc)[0], (*itc)[1]), // circle centre
                  (*itc)[2], // circle radius
                  cv::Scalar(255), // color
                  2); // thickness
               
          ++itc;       
        }

        cv::namedWindow("Detected Circles");
        cv::imshow("Detected Circles",image);

        cv::waitKey();
        return 0;
}