Im new to openCv and image processing in general. I need to draw the lines and their position in real time from an camera input like this:
i already have the image from the canny edge detection, but when applying hough line and trying to draw it to that image using the following code i found:
int main(int argc, char* argv[]){
Mat input;
Mat HSV;
Mat threshold;
Mat CannyThresh;
Mat HL;
//video capture object to acquire webcam feed
cv::VideoCapture capture;
capture.open(0);
capture.set(CV_CAP_PROP_FRAME_WIDTH, 640);
capture.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
//start an infinite loop where webcam feed is copied to cameraFeed matrix
//all operations will be performed within this loop
while (true){
capture.read(input);
cvtColor(input, HSV, COLOR_BGR2HSV); //hsv
inRange(HSV, Scalar(H_MIN, S_MIN, V_MIN), Scalar(H_MAX, S_MAX, V_MAX), threshold);//thershold
MorphOps(threshold);//morph operations on threshold image
Canny(threshold, CannyThresh, 100, 50); //canny edge detection
std::vector<Vec4i> lines;
HoughLines(CannyThresh, lines, 1, CV_PI/180, 150, 0, 0 );
for( size_t i = 0; i < lines.size(); i++ )
{
float rho = lines[i][0], theta = lines[i][1];
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000*(-b));
pt1.y = cvRound(y0 + 1000*(a));
pt2.x = cvRound(x0 - 1000*(-b));
pt2.y = cvRound(y0 - 1000*(a));
line( input, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
}
imshow("camera", input);
waitKey(30);
}
return 0;
}
i get the following exception:
1- I cant say i really understand that code yet, but can you tell me why it isnt working?.
2- if i manage to make it work, how can i get the Y coordinate of the horizontal lines? i need to know if another object is inside, below or above this one. so i need the position on the Y axis of the 2 horizontal lines on this image (the ones roughlines detected), so i can determine where the other object is regarding this "rectangle".
EDIT #1
I copied the complete code. as you can see in the second image, the debugger doesn't throw any errors. but in the console of the program it says OpenCV Error:Assertion failed (channels() == CV_MAT_CN(dtype)) in cv::Mat::copyTo, file C:\builds\master_packSlave-Win32-vc12-shared\opencv\modules\core\src\copy.cpp, line 281. Also the last call in the call stack is this: > KernelBase.dll!_RaiseException#16() Unknown, im starting to thing is an opencv problem and not a code problem, maybe something with that dll.
EDIT #2
i changed the line
std::vector<Vec4i> lines; // this line causes exception
for
std::vector<Vec2f> lines;
and now it enters the for loop. but it now gives another run time error (another segmentation fault. i think it has to do with these values:
i think they may be going off range, any ideas?
I'm not sure, but it could be the fact that you're trying to draw a line as you had a 3-channel image (using Scalar(b,g,r)), but what you really have is a single-channel image (I suppose that CannyThresh is the output of Canny()).
You can try to change the image to a colored version, using something like this:
Mat colorCannyThresh = CannyThresh.clone();
cvtColor(colorCannyThresh, colorCannyThresh, CV_GRAY2BGR);
or you can draw a line using Scalar([0~255]), changing your line() call to:
line(CannyThresh, pt1, pt2, Scalar(255), 3, CV_AA);
Again, since it's not a complete code, I'm not sure this is the case, but it could be.
About Question2, what you mean by "Y coordinate of the horizontal lines?"
Edit
After inRange(), threshold is a Mat of the same size as HSV and CV_8U type (inRange()), which means it is CV_8U*3 (3-channel -> H.S.V). Are you sure threshold, after MorphOps(), is CV_8U*1 (single-channel), as Canny() expects?
If your goal is to find what is inside a rectangle, you might want to read about minAreaRect().
Related
I'm supposed to detect the two white lines of the road with the function HoughLines. I use three trackbars in order to find the best parameters to detect ONLY the two white lines of the road. I have tried this: (the problem is that it looks like even if I change the values of the trackbars it doesn't updates the images, it is still at the first values). I'm using opencv with c++.
Without trackbars it works, but it's almost impossibile finding good values without it because I don't know how to tune the parameters and the image is pretty complex.
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/calib3d.hpp>
using namespace cv;
using namespace std;
const int kernel_size = 3;
Mat src, src_gray;
Mat dst, detected_edges;
Mat cdst;
int slider_value_one;
int slider_value_two;
int slider_value_three;
vector<Vec2f> lines; // will hold the results of the detection
static void Hough_transform(int, void*)
{
// Standard Hough Line Transform
HoughLines(detected_edges, lines, 1, CV_PI/180, 130,slider_value_one,slider_value_two); // runs the actual detectio
// Draw the lines
for( size_t i = 0; i < lines.size(); i++ )
{
float rho = lines[i][0], theta = lines[i][1];
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000*(-b));
pt1.y = cvRound(y0 + 1000*(a));
pt2.x = cvRound(x0 - 1000*(-b));
pt2.y = cvRound(y0 - 1000*(a));
line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
}
//printing
imshow("standard Hough Line Transform", cdst);
}//HoughTransform
int main(int argc, const char * argv[]) {
//-----Loads an image
src = imread("/Users/massimilianolorenzin/Documents/Progetti\ XCode/lab4/lab4/lab4/images/road2.png");
/// ---- CANNY DETECTOR
/// Convert the image to grayscale
cvtColor( src, src_gray, CV_BGR2GRAY);
/// Reduce noise with a kernel 3x3
blur( src_gray, detected_edges, Size(3,3) );
/// Canny detector
Canny( detected_edges, detected_edges, 150, 450, kernel_size );
// Copy edges to the images that will display the results in BGR
cvtColor(detected_edges, cdst, COLOR_GRAY2BGR);
/// ---- HOUGH LINE TRANSFORM
namedWindow("standard Hough Line Transform"); // Create Window
//first TrackBar
createTrackbar( "First Par", "standard Hough Line Transform", &slider_value_one, 200, Hough_transform);
Hough_transform(slider_value_one,0 );
//second TrackBar
createTrackbar( "Second Par", "standard Hough Line Transform", &slider_value_two, 100, Hough_transform);
Hough_transform(slider_value_two, 0 );
//third TrackBar
createTrackbar( "Third Par", "standard Hough Line Transform", &slider_value_three, 100, Hough_transform);
Hough_transform( slider_value_three, 0 );
//printing
imshow("Input Image",src);
imshow( "edges", detected_edges );
waitKey(0);
return 0;
HoughLines() looks doesn't answer at the values set with the trackbars. The window appear normally, slider_value_one, slider_value_two, slider_value_three have the right values because I printed and i saw them, so I don't understand why HoughLines() doesn't take the passed values.
enter image description here
Above there is the input image, while below there is the final ouput. I am asked, in this step, just to create the two lines to the side of the road, coloring the area between the two lines( like in the photo) is requested in the next step.
I've been following this tutorial to get the skew angle of an image. It seems like HoughLinesP is struggling to find lines when characters are a bit scattered on the target image.
This is my input image:
This is the lines the HoughLinesP has found:
It's not really getting most of the lines and it seems pretty obvious to me why. This is because I've set my minLineWidth to be (size.width / 2.f). The point is that because of the few lines it has found it turns out that the skew angle is also wrong. (-3.15825 in this case, when it should be something close to 0.5)
I've tried to erode my input file to make characters get closer and in this case it seems to work out, but I don't feel this is best approach for situations akin to it.
This is my eroded input image:
This is the lines the HoughLinesP has found:
This time it has found a skew angle of -0.2185 degrees, which is what I was expecting but in other hand it is losing the vertical space between lines which in my humble opinion isn't a good thing.
Is there another to pre-process this kind of image to make houghLinesP get better results for scattered characters ?
Here is the source code I'm using:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
static cv::Scalar randomColor( cv::RNG& rng )
{
int icolor = (unsigned) rng;
return cv::Scalar( icolor&255, (icolor>>8)&255, (icolor>>16)&255 );
}
void rotate(cv::Mat& src, double angle, cv::Mat& dst)
{
int len = std::max(src.cols, src.rows);
cv::Point2f pt(len/2., len/2.);
cv::Mat r = cv::getRotationMatrix2D(pt, angle, 1.0);
cv::warpAffine(src, dst, r, cv::Size(len, len));
}
double compute_skew(cv::Mat& src)
{
// Random number generator
cv::RNG rng( 0xFFFFFFFF );
cv::Size size = src.size();
cv::bitwise_not(src, src);
std::vector<cv::Vec4i> lines;
cv::HoughLinesP(src, lines, 1, CV_PI/180, 100, size.width / 2.f, 20);
cv::Mat disp_lines(size, CV_8UC3, cv::Scalar(0, 0, 0));
double angle = 0.;
unsigned nb_lines = lines.size();
for (unsigned i = 0; i < nb_lines; ++i)
{
cv::line(disp_lines, cv::Point(lines[i][0], lines[i][1]),
cv::Point(lines[i][2], lines[i][3]), randomColor(rng));
angle += atan2((double)lines[i][3] - lines[i][1],
(double)lines[i][2] - lines[i][0]);
}
angle /= nb_lines; // mean angle, in radians.
std::cout << angle * 180 / CV_PI << std::endl;
cv::imshow("HoughLinesP", disp_lines);
cv::waitKey(0);
return angle * 180 / CV_PI;
}
int main()
{
// Load in grayscale.
cv::Mat img = cv::imread("IMG_TESTE.jpg", 0);
cv::Mat rotated;
double angle = compute_skew(img);
rotate(img, angle, rotated);
//Show image
cv::imshow("Rotated", rotated);
cv::waitKey(0);
}
Cheers
I'd suggest finding individual components first (i.e., the lines and the letters), for example using cv::threshold and cv::findContours.
Then, you could drop the individual components that are narrow (i.e., the letters). You can do this using cv::floodFill for example. This should leave you with the lines only.
Effectively, getting rid of the letters might provide easier input for the Hough transform.
Try to detect groups of characters as blocks, then find contours of these blocks. Below I've done it using blurring, a morphological opening and a threshold operation.
Mat im = imread("yCK4t.jpg", 0);
Mat blurred;
GaussianBlur(im, blurred, Size(5, 5), 2, 2);
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
Mat morph;
morphologyEx(blurred, morph, CV_MOP_OPEN, kernel);
Mat bw;
threshold(morph, bw, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU);
Mat cont = Mat::zeros(im.rows, im.cols, CV_8U);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(bw, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
for(int idx = 0; idx >= 0; idx = hierarchy[idx][0])
{
drawContours(cont, contours, idx, Scalar(255, 255, 255), 1);
}
Then use Hough line transform on contour image.
With accumulator threshold 80, I get following lines that results in an angle of -3.81. This is high because of the outlier line that is almost vertical. With this approach, majority of the lines will have similar angle values except few outliers. Detecting and discarding the outliers will give you a better approximation of the angle.
HoughLinesP(cont, lines, 1, CV_PI/180, 80, size.width / 4.0f, size.width / 8.0f);
I have many images with and without text similar to the image above. I want to remove the lines at the edges and also remove noise if any present in the image.
These lines are present only at edges as I have cropped these images from a table.
You can try following approach. But i cant guarantee that all lines in your image file can be removed.
First detect all lines present in the image by applying Hough Transform
vector<Vec2f> lines;
HoughLines(img, lines, 1, CV_PI/180, 100, 0, 0 );
Then iterate through each line detected,
Get size of the image
#you may have laoded image to some file
#such as
# Mat img=imread("some_file.jpg");
int rows=img.rows;
int colms=img.cols;
Point pt3;
now you know the size of matrix, next get the centre point of the line, you can do so as below,
for( size_t i = 0; i < lines.size(); i++ )
{
float rho = lines[i][0], theta = lines[i][1];
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000*(-b));
pt1.y = cvRound(y0 + 1000*(a));
pt2.x = cvRound(x0 - 1000*(-b));
pt2.y = cvRound(y0 - 1000*(a));
pt3.x=(pt1.x+pt2.x)/2;
pt3.y=(pt1.y+pt2.y)/2;
***
//decide whether you want to remove the line,i.e change line color to
// white or not
line( img, pt1, pt2, Scalar(255,255,255), 3, CV_AA); // if you want to change
}
***once you have both centre point and size of the image, you can compare the position of the centre point is in left,right,top, bottom. You can do so by comparing with as follows. Don't use (==) allow some difference.
1. (0, cols/2) -- top of the image,
2. (rows/2,0) -- left of the image,
3. (rows, cols/2) -- bottom of the image
4. (rows/2, cols) -- right of the image
(since your image is already blurred, smoothing , erosion and dilation may not do well)
If your images are all the same, then just crop the bottom off using OpenCV...
Alternatively this link demonstrates how to remove black borders from an image.
In order to clean up the text you could try denoising
I'm trying to process the following images from a maze. My Question is about how to process the edges. I'm using OpenCV 2.4 with c++.
I'd like to know if there is any way to discriminate the edges between the floor and the wall from the lines painted in the floor?
The floor is black, the walls are white and the lines painted in the floor are white too.
What I am trying to do is distinguish between wall and marks in floor. The lines on the floor will give me a distance reference and if I can turn in the maze. While the walls just tell the limit of the halls of the maze.
here you'll find the process images I've done.
I'm using Canny and HoughLinesP functions to detect and save the lines. But as you can see in the images the program doesn't separate the lines from the edges.
The code:
vector<Vec4i> get_lines(Mat dst, Mat cdst)
{
vector<Vec4i> lines;
HoughLinesP(dst, lines, 1, CV_PI/180, 100, 50, 10 );
for( size_t i = 0; i < lines.size(); i++ )
{
Vec4i l = lines[i];
double size = norm(Mat(Point(l[0], l[1])), Mat(Point(l[2], l[3])) );
if(size > 100)
line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, CV_AA);
}
return lines;
}
And main function is:
int main(int argc, char** argv)
{
const char* filename = argc >= 2 ? argv[1] : "pic1.jpg";
Mat src = imread(filename, 0);
if(src.empty())
{
help();
cout << "can not open " << filename << endl;
return -1;
}
Mat dst, cdst;
Canny(src, dst, 50, 200, 3);
cvtColor(dst, cdst, CV_GRAY2BGR);
vector<Vec4i> lines = get_lines(dst, cdst);
imshow("source W&B", src);
imshow("edges", dst);
imshow("detected lines", cdst);
imwrite("lines.jpg",cdst);
imwrite("src.jpg",src);
imwrite("canny.jpg",dst);
waitKey();
return 0;
}
The obvious thing to try would be to compare the brightness of pixels on either side of the line.
make three regions: pixels a little distance to one side of the line, pixels a little distance to the other side of the line, and pixels close to the line. Calculate the average brightness in either region.
The walls are light grey, the floor is black and the lines are white, so
if one side is significantly brighter than the other side, it is probably an edge (and you can even tell which side is the floor),
if both sides are significantly darker than the middle it is probably a marking on the floor.
(and if the line is vertical, it is a wall-wall edge)
I'm writing a mobile app to plot the graphical representation (graphs and charts) of images of statistical data tables. currently i'm writing the table detection module of the project using OpenCV with c++.
I have already applied adaptiveThreshold and Canny to detect the largest Contour and cropped out the table. (https://i.imgur.com/clBS3dr.jpg)
and following is the code i'm using to detect the horizontal and vertical lines: Note: "Crop" is the already cropped table image(Mat)
cvtColor(crop, crop, CV_RGB2GRAY);
adaptiveThreshold(crop, crop, 255, CV_ADAPTIVE_THRESH_MEAN_C,CV_THRESH_BINARY, 31, 15);
Mat dst1, cdst1;
Canny(crop, dst1, 50, 200, 3);
cvtColor(dst1, cdst1, CV_GRAY2BGR);
vector<Vec2f> lines;
// detect lines
HoughLines(dst1, lines, 1, CV_PI/180, 200, 0, 0 );
//HoughLinesP(dst1, lines, 1, CV_PI/180, 150, 0, 0);
// draw lines
for( size_t i = 0; i < lines.size(); i++ )
{
float rho = lines[i][0], theta = lines[i][1];
//if( theta>CV_PI/180*170 || theta<CV_PI/180*10){
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000*(-b));
pt1.y = cvRound(y0 + 1000*(a));
pt2.x = cvRound(x0 - 1000*(-b));
pt2.y = cvRound(y0 - 1000*(a));
line( cdst1, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
//}
}
namedWindow("detected lines",WINDOW_NORMAL);
imshow("detected lines", cdst1);
And the result of this code comes out like this : https://i.imgur.com/yDuCqmo.jpg
What am I going wrong to the Horizontal lines only to reach half of the image?
if you are trying to extract each cell in the table you can try contour processing,
Do binary invert threshold in the source.
Find contour, here you should use RETR_EXTERNAL.
Then draw contour with CV_FILLED, here you will get mask for your table. Notice that here you should get only one contour, and assumes there wont be any noise outside the table. Or if you got multiple contour draw largest as mask.
Bitwise xor between threshold and mask
Again Find contour, with RETR_EXTERNAL option. See the drawn contour with CV_FILLED option.
Calculate bounding Rect or Rotated rect for contour for further use.
See bounding rect.
See rotated rect.
I suspect your call to HoughLines is playing a role. If you tweak the threshhold parameter, you can get more appreciable results with increased or decreased lines.