how to make hough line transform to execute faster? - c++

i have written code for lane detection using, hough line transform,lines are identified in my video file stored in my pc [which is having 1280*720 resolution],my video is running slowly,how i can make run faster?,in my code i have checked the time of execution of function hough_transform comprising of canny,cvtcolor and hough transform,up on which i am retrieving the frames, i can able to execute two frames per/sec,please help me to reduce the execution time.thanks in advance
here is the code:
#include <opencv2/highgui/highgui.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int hough_tranform(Mat src){
if(src.empty())
{
cout << "can not open " << endl;
return -1;
}
Mat dst, cdst;
Canny(src, dst, 50, 200, 3);
cvtColor(dst, cdst, COLOR_GRAY2BGR);
vector<Vec4i> lines;
HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 );
for( size_t i = 0; i < lines.size(); i++ )
{
Vec4i l = lines[i];
line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, 0);
}
imshow("detected lines", cdst);
}
int main() {
Mat frame;
string path = "C:/santhu/Wildlife.wmv";
VideoCapture capture(path);
namedWindow("my_window");
for(;;) {
capture >> frame;
hough_tranform(frame);
imshow("my_window", frame);
if(cv::waitKey(30) >= 0) break;
}
}

Playing around with the parameters of HoughLinesP function will help you to improve the performance a bit in the cost of precision. Performance will drastically reduce for this function when the image size increases.
If possible, use HoughLines instead of probabilistic approach as it is faster.
Downscaling the image using bilinear interpolation will not effect the quality of the output as hough transformation is carried out on canny edge detector output.
The steps that I would follow will be:
Read a frame.
Convert to grayScale.
Downscale the gray image.
If possible, select the ROI on the gray image on which lane is to be
detected.
Do canny on the ROI image.
Do hough transformation.
As you are doing lane detection algorithm I shall put my two cents in. Canny detection alone will not be of much help on road which contains shadows of trees etc as there will be edges detected around it. Though Probabilisitic Hough approach reduces the error in the above circumstances, (a) Limiting the theta value, (b) using sobel edge detection in which dx is given more priority than dy are some experiments worth trying.

You should downsize your image before performing edge detection, followed by Hough's Line Transform. Then you can upsize result back to the original size.

Related

How to detect how many stairs are there in an image using OpenCV C++

I'm trying to detect how many stairs I have in an image using OpenCV with C++, I've tried to do:
1-Binarization.
2-Canny Filter.
3-Hough Filter.
4-Connected Components.
I didn't get good results, do you have any idea of which methodology should I follow?
Thank you in advance.
Here is an image example.
You can obtain interesting results as follows:
compute the pixel sums horizontally; this will give you a profile (1D signal);
compute the derivative of the profile;
detect the peaks; they are positive and negative, alternatively, one of each per step.
My algorithm approach is simply like that; finding the lines of each stair will give us the stair number. To achieve that Houghline Transform can be used. You should read the documents which are linked below to be able to understand the parameter logic of the HoughLinesP function.
First problem will come accross: Houghline transform will give you many lines. To get the available lines, I eliminate the lines whose y-axis values are close to each other. I decided this threshold by considering the minimum distance between two stairs.
Note: To work on an image which is taken by vertical(90 degree) to stairs will give more better results.
Here are these steps, results, and code:
Apply GauusianBlur to blur the image. The reason of GauusianBlur choosing instead of the others I believe that GaussianBlur has a good combination with houghline transform.
Apply Canny Edge detection.
Convert image to BGR format.
Apply HoughLinesP and find all possible lines
Apply the algorithm approach which is explained above.
Get the results.
Code:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
Mat img = imread("/home/rnd/Desktop/photos/stairs.png");
imshow("Source",img);
//Apply Gaussian blur to get good results
GaussianBlur(img,img,Size(5,5),0,0);
Mat dst, out_img,control;
Canny(img, dst, 80, 240, 3);
cvtColor(dst, out_img, CV_GRAY2BGR);
cvtColor(dst, control, CV_GRAY2BGR);
vector<int> y_keeper_for_lines;
vector<Vec4i> lines;
HoughLinesP(dst, lines, 1, CV_PI/180, 30, 40, 5 );
for( size_t i = 1; i < lines.size(); i++ )
{
Vec4i l = lines[i];
line( control, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, CV_AA);
}
Vec4i l = lines[0];
line( out_img, Point(0, l[1]), Point(img.cols, l[1]), Scalar(0,0,255), 3, CV_AA);
y_keeper_for_lines.push_back(l[1]);
int okey = 1;
int stair_counter = 1;
for( size_t i = 1; i < lines.size(); i++ )
{
Vec4i l = lines[i];
for(int m:y_keeper_for_lines)
{
if(abs(m-l[1])<15)
okey = 0;
}
if(okey)
{
line( out_img, Point(0, l[1]), Point(img.cols, l[1]), Scalar(0,0,255), 3, CV_AA);
y_keeper_for_lines.push_back(l[1]);
stair_counter++;
}
okey = 1;
}
putText(out_img,"Stair number:" + to_string(stair_counter),Point(40,60),FONT_HERSHEY_SIMPLEX,1.5,Scalar(0,255,0),2);
imshow("Before", img);
imshow("Control", control);
imshow("detected lines", out_img);
waitKey(0);
return 0;
}
Results:
After Gaussian:
HoughLinesP before algorithm:
After algorithm:

Image Segmentation - Remove Unwanted Pixels in C++

I'm working on image processing. Firstly, I have to make image segmentation and extract only boundary of image. Then, This image is converted to freeman chain code. The part of freeman chain code is Okay. But, When I make a segmentation of image, inside of the image remains some unwanted white pixels. And thus, the next step,which is freeman chain code, is not being succesfull. I mean, It gives incorrect chain code because of unwanted pixels. So, I have to remove unwanted pixels from inside of image. I will share my code and can you tell me how i can change in this code or what kind of a correct code can i should write for this filter ? Code is here :
#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>
#include <opencv2/imgproc/imgproc_c.h>
using namespace cv;
using namespace std;
int main(){
Mat img = imread("<image-path>");
Mat gray;
cvtColor(img,gray,CV_BGR2GRAY);
Mat binary;
threshold(gray,binary, 200, 255, CV_THRESH_BINARY);
Mat kernel = (Mat_<float>(3,3) <<
1, 1, 1,
1, -8, 1,
1, 1, 1);
Mat imgLaplacian;
Mat sharp= binary;
filter2D(binary, imgLaplacian, CV_32F, kernel);
binary.convertTo(sharp, CV_32F);
Mat imgResult = sharp - imgLaplacian;
imgResult.convertTo(imgResult, CV_8UC1);
imgLaplacian.convertTo(imgLaplacian, CV_8UC1);
//Find contours
vector<vector<Point>> contours;
vector <uchar> chaincode;
vector <char> relative;
findContours(imgLaplacian,contours, CV_RETR_LIST, CHAIN_APPROX_NONE);
for (size_t i=0; i<contours.size();i++){
chain_freeman(contours[i],chaincode);
FileStorage fs("<file-path>", 1);
fs << "chain" << chaincode;
}
for (size_t i=0; i<chaincode.size()-1; i++){
int relative1 = 0;
relative1 = abs(chaincode[i]-chaincode[i+1]);
cout << relative1;
for (int j=0; j<relative1; j++){
}
relative.push_back(relative1);
FileStorage fs("<file-path>", 1);
fs << "chain" << relative;
}
imshow("binary",imgLaplacian);
cvWaitKey();
return 0;
}
original image
Result
In this result, I want to remove white pixel inside of the image. I tried all fiter in opencv but I could not achieve. It's very important because of chain code.
Okay, now I see it. As said, you can ignore small contours simply by their length. For the rest, you need maximally thin contours (seems like 4-connected is the case). There you have couple options:
1) thinning of the current. If you can grab Matlab's lookup table, you can then load it into OpenCV as How to use Matlab's 512 element lookup table array in OpenCV?
2) it's pretty simple to label the boundary pixels by hand after binarization. To make it more efficient, you can first fill small cavities (islets) by applying connected component labeling on the background (using opposite connectivity this time, 8 it is).
2i & 2ii) If you do the labeling by hand, you can either continue collecting the contour vector by hand or switch to cv::findContours
Hope this helps

Detecting Road from satellite image in OpenCV

I'm trying to detect roads from a satellite image! It can be any type of paved/asphalt road. I'm using OpenCV! The way I am trying is, first I used Canny to detect the edges, the I am trying to apply hough transform to detect the straight lines from the edges. Then I planned to detect circles to detect the curves of the roads. The problem I'm facing is, after doing canny, hough is not working. Here is my code so far:
#include <iostream>
#include <math.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main()
{
//read an image
cv::Mat image = cv::imread("img2.jpg");
//create image window named "My Image"
cv::namedWindow("My Image");
//show the image on the window
cv::imshow("My Image", image);
cv::Mat contours,hough;
//canny
cv::Canny(image, contours, 0, 100);
cv::namedWindow("My Image2");
cv::imshow("My Image2", contours);
// Hough tranform for line detection
std::vector<cv::Vec2f> lines;
cv::HoughLines(contours, lines, 1, CV_PI/180, 80, 0, 0);
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 < CV_PI/4. || theta > 3.*CV_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( image, 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(image, pt1, pt2, cv::Scalar(255), 1);
}
++it;
}
//show lines
cv::namedWindow("My Image3");
cv::imshow("My Image3", hough);
//wait key for 5000ms
cv::waitKey(80000);
return 0;
}
In this code, I'm getting an error under "result" at line cv::Point pt2((rho-result.rows*sin(theta))/cos(theta),result.rows);
And another error under "result" at line cv::Point pt2(result.cols,(rho-result.cols*cos(theta))/sin(theta));
I can't figure it out what errors are those and what are the solutions! Any help would be appreciated :)
Also I'm totally new at computer vision, if you have any other easier and simpler way to accomplish my goal please feel free to share it :)
For your help I'm giving the sample image and the image of errors:
https://drive.google.com/open?id=0B4qYRvG5emZDWXhNV2V2djZWdUk
Error is for the errors, Canny is after performing canny algorithm and input is the sample image I took!
NOTE: I'm following OpenCV cookbook for my codes!

OpenCV histogram of an irregular shape

I'm comparatively new to OpenCV. I was wondering if it is possible to get histogram of a contour (which can be a perfect rectangular or irregular in shape) found by findcontour.
Thanks in advance.
Edit:
This is what exactly I'm trying to achieve. I want to analyse area in contour to detect defects (by analyzing histogram of an area ?) and declare piece defective or good. Images attached.
Good sample. (Contour detected is outlined in gray color)
Defective sample. (defect around top left corner)
You may probably misuse the histogram.
Contour of an image should be a binary-valued, color-less matrix which does not represent grayscale-level of pixels, but the boundaries.
Meanwhile, histogram is a tool for analyzing how grayscale-valued of pixels distribute in your 2D image, isn't it?
Thus, why you want to profile the histogram of a binary-valued matrix which might not help you analyzing the image? Histogram is not the right t ool for the contour analysis though.
What you may get from the histogram should just be only a two-bar histogram because the contoured matrix contains only binary values. This might not be helpful for analysis.
Here's an other way, using morphological operations.
#include <string>
#include <iostream>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
cv::Mat make_element(int morph_size, int elem_type)
{
cv::Size sz{2*morph_size+1, 2*morph_size+1};
cv::Point pt{morph_size, morph_size};
cv::Mat element{getStructuringElement(elem_type, sz, pt)};
return element;
}
int main(int argc, char **argv)
{
std::string fn{argv[1]};
cv::Mat src{cv::imread(fn)}, dst, mask[3];
if (!src.data) {
std::cerr << "No image data :(" << std::endl;
return -1;
}
// Clean out noise
cv::Mat elem1{make_element(5, cv::MORPH_RECT)};
cv::morphologyEx(src, dst, cv::MORPH_OPEN, elem1);
// Close the hole, then XOR with original
cv::Mat elem2{make_element(45, cv::MORPH_ELLIPSE)};
morphologyEx(dst, dst, cv::MORPH_CLOSE, elem2);
cv::bitwise_xor(src, dst, dst);
// Clean out noise (again)
cv::Mat elem3{make_element(1, cv::MORPH_RECT)};
cv::morphologyEx(dst, dst, cv::MORPH_OPEN, elem3);
// Mark the hole
cv::split(dst, mask);
cv::bitwise_xor(src, dst, dst, mask[0]);
// Overlay
cv::split(dst, mask);
cv::Mat empty{dst.size(), CV_8UC1};
std::vector<cv::Mat> v{empty, empty, mask[0]};
cv::merge(v, dst);
cv::bitwise_or(src, dst, dst);
cv::namedWindow("Defect (ESC to quit)", cv::WINDOW_NORMAL);
cv::startWindowThread();
cv::imshow("Defect (ESC to quit)", dst);
while (true) {
int k = cv::waitKey(100) & 0xff;
if (k == 27) {
break;
}
}
cv::destroyAllWindows();
return 0;
};
Some additional reading:
Shapiro/Stockman, Finding gear defects, Chapter 3
OpenCV morphology tutorial

Opencv: Edge detection, Dilation and Mass ceter drawing

My work is based on images with an array of dots (Fig. 1), and the final result is shown in Fig. 4. I will explain my work step by step.
Fig. 1 Original image
Step 1: Detect the edge of every object, including the dots and a "ring" that I want to delete for better performance. And the result of edge detection is shown in Fig.2. I used Canny edge detector but it didn't work well with some light-gray dots. My first question is how to close the contours of dots and reduce other noise as much as possible?
Fig. 2 Edge detection
Step 2: Dilate every object. I didn't find a good way to fill holes, so I dilate them directly. As shown in Fig.3, holes seem to be enlarged too much and so does other noise. My second question is how to fill or dilate the holes in order to make them be filled circles in the same/similar size?
Fig. 3 Dilation
Step 3: Find and draw the mass center of every dot. As shown in Fig. 4, due to the coarse image processing, there exist mark of the "ring" and some of dots are shown in two white pixels. The result wanted should only show the dots and one white pixel for one dot.
Fig. 4: Mass centers
Here is my code for these 3 steps. Can anyone help to make my work better?
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
using namespace std;
using namespace cv;
// Global variables
Mat src, edge, dilation;
int dilation_size = 2;
// Function header
void thresh_callback(int, void*);
int main(int argc, char* argv)
{
IplImage* img = cvLoadImage("c:\\dot1.bmp", 0); // dot1.bmp = Fig. 1
// Perform canny edge detection
cvCanny(img, img, 33, 100, 3);
// IplImage to Mat
Mat imgMat(img);
src = img;
namedWindow("Step 1: Edge", CV_WINDOW_AUTOSIZE);
imshow("Step 1: Edge", src);
// Apply the dilation operation
Mat element = getStructuringElement(2, Size(2 * dilation_size + 1, 2 * dilation_size + 1),
Point(dilation_size, dilation_size)); // dilation_type = MORPH_ELLIPSE
dilate(src, dilation, element);
// imwrite("c:\\dot1_dilate.bmp", dilation);
namedWindow("Step 2: Dilation", CV_WINDOW_AUTOSIZE);
imshow("Step 2: Dilation", dilation);
thresh_callback( 0, 0 );
waitKey(0);
return 0;
}
/* function thresh_callback */
void thresh_callback(int, void*)
{
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
// Find contours
findContours(dilation, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
// Get the moments
vector<Moments> mu(contours.size());
for(int i = 0; i < contours.size(); i++) {
mu[i] = moments(contours[i], false);
}
// Get the mass centers
vector<Point2f> mc(contours.size());
for(int i = 0; i < contours.size(); i++) {
mc[i] = Point2f(mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00);
}
// Draw mass centers
Mat drawing = Mat::zeros(dilation.size(), CV_8UC1);
for( int i = 0; i< contours.size(); i++ ) {
Scalar color = Scalar(255, 255, 255);
line(drawing, mc[i], mc[i], color, 1, 8, 0);
}
namedWindow("Step 3: Mass Centers", CV_WINDOW_AUTOSIZE);
imshow("Step 3: Mass Centers", drawing);
}
There are a few things you can do to improve your results. To reduce noise in the image, you can apply a median blur before applying the Canny operator. This is a common de-noising technique. Also, try to avoid using the C API and IplImage.
cv::Mat img = cv::imread("c:\\dot1.bmp", 0); // dot1.bmp = Fig. 1
cv::medianBlur(img, img, 7);
// Perform canny edge detection
cv::Canny(img, img, 33, 100);
This significantly reduces the amount of noise in your edge image:
To better retain the original sizes of your dots, you can perform a few iterations of morphological closing with a smaller kernel rather than dilation. This will also reduce joining of the dots with the circle:
// This replaces the call to dilate()
cv::morphologyEx(src, dilation, MORPH_CLOSE, cv::noArray(),cv::Point(-1,-1),2);
This will perform two iterations with a 3x3 kernel, indicated by using cv::noArray().
The result is cleaner, and the dots are completely filled:
Leaving the rest of your pipeline unmodified gives the final result. There are still a few spurious mass centers from the circle, but considerably fewer than the original method:
If you wanted to attempt removing the circle from the results entirely, you could try using cv::HoughCircles() and adjusting the parameters until you get a good result. This might have some difficulties because the entire circle is not visible in the image, only segments, but I recommend you experiment with it. If you did detect the innermost circle, you could use it as a mask to filter out external mass centers.
how to close contours of dots? use drawContours method with filled drawing option (CV_FILLED or thickness = -1)
reduce noise? use one of the blurring (low pass filtering) methods.
similar size? use erosion after dilation = morphological closing.
one dot for one circle, output without outer ring? find average of all contour areas. erase contours having big difference to this value. output the remaining centers.
Aurelius already mentioned most of these, but since this problem is quiet interesting, I will probably try and post a complete solution when I have enough time. Good luck.