Approximate photo of a simple drawing using lines - opencv

As an input I have a photo of a simple symbol, e.g.: https://www.dropbox.com/s/nrmsvfd0le0bkke/symbol.jpg
I would like to detect the straight lines in it, like points of start and ends of the lines. In this case, assuming the top left of the symbol is (0,0), the lines would be defined like this:
start end (coordinates of beginning and end of a line)
1. (0,0); (0,10) (vertical line)
2. (0,10); (15, 15)
3. (15,15); (0, 20)
4. (0,20); (0,30)
How can I do it (pereferably using OpenCV)? I though about Hough lines, but they seem to be good for perfect thin straight lines, which is not the case in a drawing. I'll probably work on binarized image, too.

Give a try on this,
Apply thinning algorithm on threshold image.
Find contours.
approxPolyDP for the found contour.
See some reference:
approxpolydp-for-edge-maps
Creating Bounding boxes and circles for contours

maybe you can work on this one.
assume a perfect binarization:
run HoughLinesP
(not implemented) try to group those detected lines
I used this code:
int main()
{
cv::Mat image = cv::imread("HoughLinesP_perfect.png");
cv::Mat gray;
cv::cvtColor(image,gray,CV_BGR2GRAY);
cv::Mat output; image.copyTo(output);
cv::Mat g_thres = gray == 0;
std::vector<cv::Vec4i> lines;
//cv::HoughLinesP( binary, lines, 1, 2*CV_PI/180, 100, 100, 50 );
// cv::HoughLinesP( h_thres, lines, 1, CV_PI/180, 100, image.cols/2, 10 );
cv::HoughLinesP( g_thres, lines, 1, CV_PI/(4*180.0), 50, image.cols/20, 10 );
for( size_t i = 0; i < lines.size(); i++ )
{
cv::line( output, cv::Point(lines[i][0], lines[i][3]),
cv::Point(lines[i][4], lines[i][3]), cv::Scalar(155,255,155), 1, 8 );
}
cv::imshow("g thres", g_thres);
cv::imwrite("HoughLinesP_out.png", output);
cv::resize(output, output, cv::Size(), 0.5,0.5);
cv::namedWindow("output"); cv::imshow("output", output);
cv::waitKey(-1);
std::cout << "finished" << std::endl;
return 0;
}
EDIT:
updated code with simple line clustering (`minimum_distance function taken from SO):
giving this result:
float minimum_distance(cv::Point2f v, cv::Point2f w, cv::Point2f p) {
// Return minimum distance between line segment vw and point p
const float l2 = cv::norm(w-v) * cv::norm(w-v); // i.e. |w-v|^2 - avoid a sqrt
if (l2 == 0.0) return cv::norm(p-v); // v == w case
// Consider the line extending the segment, parameterized as v + t (w - v).
// We find projection of point p onto the line.
// It falls where t = [(p-v) . (w-v)] / |w-v|^2
//const float t = dot(p - v, w - v) / l2;
float t = ((p-v).x * (w-v).x + (p-v).y * (w-v).y)/l2;
if (t < 0.0) return cv::norm(p-v); // Beyond the 'v' end of the segment
else if (t > 1.0) return cv::norm(p-w); // Beyond the 'w' end of the segment
const cv::Point2f projection = v + t * (w - v); // Projection falls on the segment
return cv::norm(p - projection);
}
int main()
{
cv::Mat image = cv::imread("HoughLinesP_perfect.png");
cv::Mat gray;
cv::cvtColor(image,gray,CV_BGR2GRAY);
cv::Mat output; image.copyTo(output);
cv::Mat g_thres = gray == 0;
std::vector<cv::Vec4i> lines;
cv::HoughLinesP( g_thres, lines, 1, CV_PI/(4*180.0), 50, image.cols/20, 10 );
float minDist = 100;
std::vector<cv::Vec4i> lines_filtered;
for( size_t i = 0; i < lines.size(); i++ )
{
bool keep = true;
int overwrite = -1;
cv::Point2f a(lines[i][0], lines[i][6]);
cv::Point2f b(lines[i][7], lines[i][3]);
float lengthAB = cv::norm(a-b);
for( size_t j = 0; j < lines_filtered.size(); j++ )
{
cv::Point2f c(lines_filtered[j][0], lines_filtered[j][8]);
cv::Point2f d(lines_filtered[j][9], lines_filtered[j][3]);
float distCDA = minimum_distance(c,d,a);
float distCDB = minimum_distance(c,d,b);
float lengthCD = cv::norm(c-d);
if((distCDA < minDist) && (distCDB < minDist))
{
if(lengthCD >= lengthAB)
{
keep = false;
}
else
{
overwrite = j;
}
}
}
if(keep)
{
if(overwrite >= 0)
{
lines_filtered[overwrite] = lines[i];
}
else
{
lines_filtered.push_back(lines[i]);
}
}
}
for( size_t i = 0; i < lines_filtered.size(); i++ )
{
cv::line( output, cv::Point(lines_filtered[i][0], lines_filtered[i][10]),
cv::Point(lines_filtered[i][11], lines_filtered[i][3]), cv::Scalar(155,255,155), 2, 8 );
}
cv::imshow("g thres", g_thres);
cv::imwrite("HoughLinesP_out.png", output);
cv::resize(output, output, cv::Size(), 0.5,0.5);
cv::namedWindow("output"); cv::imshow("output", output);
cv::waitKey(-1);
std::cout << "finished" << std::endl;
return 0;
}

You should try the Hough Line Transform. And here is an example from this website
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
Mat src = imread("building.jpg", 0);
Mat dst, cdst;
Canny(src, dst, 50, 200, 3);
cvtColor(dst, cdst, CV_GRAY2BGR);
vector<Vec2f> lines;
// detect lines
HoughLines(dst, 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];
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);
}
imshow("source", src);
imshow("detected lines", cdst);
waitKey();
return 0;
}
With this you should be able to tweak and get the proprieties you are looking for (vertices).

Related

Comparing openCv PnP with openGv PnP

I am trying to build a test project to compare the openCv solvePnP implementation with the openGv one.
the opencv is detailed here:
https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#solvepnp
and the openGv here:
https://laurentkneip.github.io/opengv/page_how_to_use.html
Using the opencv example code, I am finding a chessboard in an image, and constructing the matching 3d points. i run the cv pnp, then set up the Gv solver. the cv pnp runs fine, and prints the values:
//rotation
-0.003040771263293328, 0.9797142824436152, -0.2003763421317906;
0.0623096853748876, 0.2001735322445355, 0.977777101438374]
//translation
[-12.06549797067309;
-9.533070368412945;
37.6825295047483]
I test by reprojecting the 3d points, and it looks good.
The Gv Pnp, however, prints nan for all values. i have tried to follow the example code, but I must be making a mistake somewhere. The code is:
int main(int argc, char **argv) {
cv::Mat matImg = cv::imread("chess.jpg");
cv::Size boardSize(8, 6);
//Construct the chessboard model
double squareSize = 2.80;
std::vector<cv::Point3f> objectPoints;
for (int i = 0; i < boardSize.height; i++) {
for (int j = 0; j < boardSize.width; j++) {
objectPoints.push_back(
cv::Point3f(double(j * squareSize), float(i * squareSize), 0));
}
}
cv::Mat rvec, tvec;
cv::Mat cameraMatrix, distCoeffs;
cv::FileStorage fs("CalibrationData.xml", cv::FileStorage::READ);
fs["cameraMatrix"] >> cameraMatrix;
fs["dist_coeffs"] >> distCoeffs;
//Found chessboard corners
std::vector<cv::Point2f> imagePoints;
bool found = cv::findChessboardCorners(matImg, boardSize, imagePoints, cv::CALIB_CB_FAST_CHECK);
if (found) {
cv::drawChessboardCorners(matImg, boardSize, cv::Mat(imagePoints), found);
//SolvePnP
cv::solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs, rvec, tvec);
drawAxis(matImg, cameraMatrix, distCoeffs, rvec, tvec, squareSize);
}
//cv to matrix
cv::Mat R;
cv::Rodrigues(rvec, R);
std::cout << "results from cv:" << R << tvec << std::endl;
//START OPEN GV
//vars
bearingVectors_t bearingVectors;
points_t points;
rotation_t rotation;
//add points to the gv type
for (int i = 0; i < objectPoints.size(); ++i)
{
point_t pnt;
pnt.x() = objectPoints[i].x;
pnt.y() = objectPoints[i].y;
pnt.z() = objectPoints[i].z;
points.push_back(pnt);
}
/*
K is the common 3x3 camera matrix that you can compose with cx, cy, fx, and fy.
You put the image point into homogeneous form (append a 1),
multiply it with the inverse of K from the left, which gives you a normalized image point (a spatial direction vector).
You normalize that to norm 1.
*/
//to homogeneous
std::vector<cv::Point3f> imagePointsH;
convertPointsToHomogeneous(imagePoints, imagePointsH);
//multiply by K.Inv
for (int i = 0; i < imagePointsH.size(); i++)
{
cv::Point3f pt = imagePointsH[i];
cv::Mat ptMat(3, 1, cameraMatrix.type());
ptMat.at<double>(0, 0) = pt.x;
ptMat.at<double>(1, 0) = pt.y;
ptMat.at<double>(2, 0) = pt.z;
cv::Mat dstMat = cameraMatrix.inv() * ptMat;
//store as bearing vector
bearingVector_t bvec;
bvec.x() = dstMat.at<double>(0, 0);
bvec.y() = dstMat.at<double>(1, 0);
bvec.z() = dstMat.at<double>(2, 0);
bvec.normalize();
bearingVectors.push_back(bvec);
}
//create a central absolute adapter
absolute_pose::CentralAbsoluteAdapter adapter(
bearingVectors,
points,
rotation);
size_t iterations = 50;
std::cout << "running epnp (all correspondences)" << std::endl;
transformation_t epnp_transformation;
for (size_t i = 0; i < iterations; i++)
epnp_transformation = absolute_pose::epnp(adapter);
std::cout << "results from epnp algorithm:" << std::endl;
std::cout << epnp_transformation << std::endl << std::endl;
return 0;
}
Where am i going wrong in setting up the openGv Pnp solver?
Years later, i had this same issue, and solved it. To convert openCv to openGV bearing vectors, you can do this:
bearingVectors_t bearingVectors;
std::vector<cv::Point2f> dd2;
const int N1 = static_cast<int>(dd2.size());
cv::Mat points1_mat = cv::Mat(dd2).reshape(1);
// first rectify points and construct homogeneous points
// construct homogeneous points
cv::Mat ones_col1 = cv::Mat::ones(N1, 1, CV_32F);
cv::hconcat(points1_mat, ones_col1, points1_mat);
// undistort points
cv::Mat points1_rect = points1_mat * cameraMatrix.inv();
// compute bearings
points2bearings3(points1_rect, &bearingVectors);
using this function for the final conversion:
// Convert a set of points to bearing
// points Matrix of size Nx3 with the set of points.
// bearings Vector of bearings.
void points2bearings3(const cv::Mat& points,
opengv::bearingVectors_t* bearings) {
double l;
cv::Vec3f p;
opengv::bearingVector_t bearing;
for (int i = 0; i < points.rows; ++i) {
p = cv::Vec3f(points.row(i));
l = std::sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]);
for (int j = 0; j < 3; ++j) bearing[j] = p[j] / l;
bearings->push_back(bearing);
}
}

How to find a more accurate ellipse based on the current detected ellipse

I fitted an ellipse based on edges of extracted red ball. But it's not accurate.
I extracted this red ball based on HSV Color Space, but it always ignores the contour of this ball. (Perhaps because color of contour is much darker).
Any good ideas to let me fit a better ellipse for this ball? I want to find an ellipse which can embrace the red ball as accurate as possible.
It will be better if I can use existing functions of OpenCV.
I have fixed this problem. It is still unstable, but at most of time it works.
source image. All of those images can be detected: https://www.dropbox.com/sh/daerty94kv5k2n7/AABu9Axewe6mL0NdEX2nG5MIa?dl=0
Fit ellipse based on color
Re-fit ellipse based on color and edges
The Video link: https://www.youtube.com/watch?v=q0TQYREm9uA
Here is source code:
#include <iostream>
#include "opencv2/opencv.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
cv::Mat capturedImage = imread(argv[1]);
if( capturedImage.empty() )
{
cout << "Couldn't open image " << argv[1] << "\nUsage: fitellipse <image_name>\n";
return 0;
}
/*============================= Phase 1: Translate Color Space from RGB to HSV =====================================================*/
cv::Mat imgHSV;
cv::cvtColor(capturedImage, imgHSV, cv::COLOR_BGR2HSV); //Convert the captured frame from BGR to HSV
cv::Mat imgGray;
cv::cvtColor(capturedImage, imgGray, CV_RGB2GRAY);
cv::Mat imgThresholded;
cv::inRange(imgHSV, cv::Scalar(160, 80, 70), cv::Scalar(179, 255, 255), imgThresholded); //Threshold the image
//morphological opening
cv::erode(imgThresholded, imgThresholded, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(7, 7)) );
cv::dilate( imgThresholded, imgThresholded, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(7, 7)) );
//morphological closing (removes small holes from the foreground)
cv::dilate( imgThresholded, imgThresholded, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(7, 7)) );
cv::erode(imgThresholded, imgThresholded, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(7, 7)) );
namedWindow("imgThresholded", WINDOW_NORMAL);
imshow("imgThresholded", imgThresholded);
/*============================= Phase 2: Fit a coarse ellipse based on red color ======================================================*/
vector<vector<cv::Point> > contours;
cv::findContours(imgThresholded, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cv::Point(0,0));
size_t index = 0;
size_t largestSize = 0;
for(size_t i = 0; i < contours.size(); i++)
{
if (contours[i].size() > largestSize)
{
largestSize = contours[i].size();
index = i;
}
}
if (contours[index].size() < 6)
{
cout << "Do not have enough points" << endl;
return -1;
}
cv::Mat imgContour;
cv::Mat(contours[index]).convertTo(imgContour, CV_32F);
cv::RotatedRect coarseEllipse = cv::fitEllipse(imgContour);
cv::Mat capturedImageClone = capturedImage.clone();
ellipse(capturedImageClone, coarseEllipse.center, coarseEllipse.size*0.5f, coarseEllipse.angle, 0.0, 360.0, cv::Scalar(0,255,255), 3, CV_AA);
namedWindow("capturedImageClone", CV_WINDOW_NORMAL);
imshow("capturedImageClone", capturedImageClone);
/*============================= Phase 3: Re-fit a final ellipse based on combination of color and edge ===============================*/
double cxc = coarseEllipse.center.x;
double cyc = coarseEllipse.center.y;
double ca = coarseEllipse.size.height/2;
double cb = coarseEllipse.size.width/2;
cv::Mat mask(capturedImage.rows, capturedImage.cols, CV_8UC3, cv::Scalar(0,0,0));
cv::circle(mask, cv::Point(coarseEllipse.center.x, coarseEllipse.center.y), coarseEllipse.size.height/2 + 100, cv::Scalar(255,255,255), -1);
cv::Mat imgMask;
cv::Mat edges;
cv::bitwise_and(capturedImage, mask, imgMask);
namedWindow("imgMask", CV_WINDOW_NORMAL);
imshow("imgMask", imgMask);
cv::GaussianBlur(imgMask, edges, cv::Size(5,5), 0);
cv::Canny(edges, edges, 50, 100);
namedWindow("edges", CV_WINDOW_NORMAL);
imshow("edges", edges);
cv::findContours(edges, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cv::Point(0,0));
index = -1;
double centerDistance = (numeric_limits<double>::max)();
double abRatio = (numeric_limits<double>::max)();
cv::RotatedRect finalEllipse;
for (size_t i = 0; i < contours.size(); i++)
{
if (contours[i].size() < 500 || i == contours.size() - 1 || i == contours.size() - 2)
continue;
cv::Mat(contours[i]).convertTo(imgContour, CV_32F);
cv::RotatedRect tmpEllipse = cv::fitEllipse(imgContour);
double txc = tmpEllipse.center.x;
double tyc = tmpEllipse.center.y;
double ta = tmpEllipse.size.height/2;
double tb = tmpEllipse.size.width/2;
double tmpDis = (cxc - txc) * (cxc - txc) + (cyc - tyc) * (cyc - tyc);
if (tmpDis < centerDistance && fabs(tb/ta - 1) < abRatio && ta > ca && tb > cb)
{
centerDistance = tmpDis;
abRatio = fabs(tb/ta - 1);
index = i;
finalEllipse = tmpEllipse;
}
}
if (index == -1)
finalEllipse = coarseEllipse;
ellipse(capturedImage, finalEllipse.center, finalEllipse.size*0.5f, finalEllipse.angle, 0.0, 360.0, cv::Scalar(0,255,255), 3, CV_AA);
double xc = finalEllipse.center.x; // center x
double yc = finalEllipse.center.y; // center y
double theta = finalEllipse.angle; // rotation angle theta
double a = finalEllipse.size.height / 2; // semi-major axis: a
double b = finalEllipse.size.width / 2; // semi-minor axis: b
double A = a * a * sin(theta) * sin(theta) + b * b * cos(theta) * cos(theta);
double B = 2 * (b * b - a * a) * sin(theta) * cos(theta);
double C = a * a * cos(theta) * cos(theta) + b * b * sin(theta) * sin(theta);
double D = -2 * A * xc - B * yc;
double E = -B * xc - 2 * C * yc;
double F = A * xc * xc + B * xc * yc + C * yc * yc - a * a * b * b;
A = A/F;
B = B/F;
C = C/F;
D = D/F;
E = E/F;
F = F/F;
double ellipseArray[3][3] = {{A, B/2, D/2},
{B/2, C, E/2},
{D/2, E/2, F}};
cv::Mat ellipseMatrix(3,3,CV_64FC1, ellipseArray);
cout << ellipseMatrix << endl;
namedWindow("capturedImage", CV_WINDOW_NORMAL);
imshow("capturedImage", capturedImage);
imwrite(argv[2],capturedImage);
imwrite(argv[3],edges);
imwrite(argv[4],capturedImageClone);
imwrite(argv[5],imgMask);
waitKey(0);
return 0;
}

How to capture hair wisp structure from an image?

I want to draw a cue from a specified point along its gradient direction to capture structure of hair wisp. Like Figure2. and Figure3. from an ACM paper, I linked here: Single-View Hair Modeling for Portrait Manipulation. Now I draw an orientation map by gradients, but the results look very chaotic.
This is my code:
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argv, char* argc[])
{
Mat image = imread("wavy.jpg", 0);
if(!image.data)
return -1;
Mat sobelX1;
Sobel(image, sobelX1, CV_8U, 1, 0, 3);
//imshow("X direction", sobelX);
Mat sobelY1;
Sobel(image, sobelY1, CV_8U, 1, 0, 3);
//imshow("Y direction", sobelY);
Mat sobelX, sobelY;
sobelX1.convertTo(sobelX, CV_32F, 1./255);
sobelY1.convertTo(sobelY, CV_32F, 1./255);
double l_max = -10;
for (int y = 0; y < image.rows; y+=3) // First iteration, to compute the maximum l (longest flow)
{
for (int x = 0; x < image.cols; x+=3)
{
double dx = sobelX.at<float>(y, x); // Gets X component of the flow
double dy = sobelY.at<float>(y, x); // Gets Y component of the flow
CvPoint p = cvPoint(y, x);
double l = sqrt(dx*dx + dy*dy); // This function sets a basic threshold for drawing on the image
if(l>l_max) l_max = l;
}
}
for (int y = 0; y < image.rows; y+=3)
{
for (int x = 0; x < image.cols; x+=3)
{
double dx = sobelX.at<float>(y, x); // Gets X component of the flow
double dy = sobelY.at<float>(y, x); // Gets Y component of the flow
CvPoint p = cvPoint(x, y);
double l = sqrt(dx*dx + dy*dy); // This function sets a basic threshold for drawing on the image
if (l > 0)
{
double spinSize = 5.0 * l/l_max; // Factor to normalise the size of the spin depending on the length of the arrow
CvPoint p2 = cvPoint(p.x + (int)(dx), p.y + (int)(dy));
line(image, p, p2, CV_RGB(0,255,0), 1, CV_AA);
double angle; // Draws the spin of the arrow
angle = atan2( (double) p.y - p2.y, (double) p.x - p2.x);
p.x = (int) (p2.x + spinSize * cos(angle + 3.1416 / 4));
p.y = (int) (p2.y + spinSize * sin(angle + 3.1416 / 4));
line(image, p, p2, CV_RGB(0,255,0), 1, CV_AA, 0 );
}
}
}
imshow("Orientation Map", image);
waitKey(0);
return 0;
}
Can any one give me some hints?
Your Sobels are the same while they supposed to have different code for x and y. 0, 1 and 1, 0.on top of that you loose resolution and sign by specifying cv8U as depth inSobel and only then converting to float. Also please provide input resolution and your outcome image.

opencv square detection radiant floor prob

working on square detection. the problem is on the radiant floor. as you can see pictures.
any idea for solve this problem ?
thank you.
source image :
output :
source code:
void EdgeDetection::find_squares(const cv::Mat& image,
vector >& squares,cv::Mat& outputFrame) {
unsigned long imageSize = (long) (image.rows * image.cols) / 1000;
if (imageSize > 1200) RESIZE = 9;
else if (imageSize > 600) RESIZE = 5;
else if (imageSize > 300) RESIZE = 3;
else RESIZE = 1;
Mat src(Size(image.cols / RESIZE, image.rows / RESIZE),CV_YUV420sp2BGR);
// Resize src to img size
resize(image, src, src.size() ,0.5, 0.5, INTER_LINEAR);
Mat imgeorj=image;
const int N = 10;//11;
Mat pyr, timg, gray0(src.size(), CV_8U), gray;
// down-scale and upscale the image to filter out the noise
pyrDown(src, pyr, Size(src.cols / 2, src.rows / 2));
pyrUp(pyr, timg, src.size());
#ifdef blured
Mat blurred(src);
medianBlur(src, blurred, 15);
#endif
vector<vector<Point> > contours;
// find squares in every color plane of the image
for ( int c = 0; c < 3; ++c) {
int ch[] = {c, 0};
mixChannels(&timg, 1, &gray0, 1, ch, 1);
// try several threshold levels
for ( int l = 0; l < N; ++l) {
// hack: use Canny instead of zero threshold level.
// Canny helps to catch squares with gradient shading
if (l == 0) {
// apply Canny. Take the upper threshold from slider
// and set the lower to 0 (which forces edges merging)
// Canny(gray0, gray, 0, thresh, 5);
// Canny(gray0, gray, (10+l), (10+l)*3, 3);
Canny(gray0, gray,50, 200, 3 );
// dilate canny output to remove potential
// holes between edge segments
dilate(gray, gray, Mat(), Point(-1, -1));
//erode(gray, gray, Mat(), Point(-1, -1), 1);
} else {
// apply threshold if l!=0:
// tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
gray = gray0 >= (l + 1) * 255 / N;
}
// find contours and store them all as a list
findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
vector<Point> approx;
// test each contour
for (size_t i = 0; i < contours.size(); ++i) {
// approximate contour with accuracy proportional
// to the contour perimeter
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true) * 0.02, true);
if (approx.size() == 4 &&
fabs(contourArea(Mat(approx))) > 5000 &&
isContourConvex(Mat(approx))) {
float maxCosine = 0;
for (register int j = 2; j < 5; ++j) {
// find the maximum cosine of the angle between joint edges
float cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
maxCosine = MAX(maxCosine, cosine);
}
// if cosines of all angles are small
// (all angles are ~90 degree) then write quandrange
// vertices to resultant sequence
if (maxCosine < 0.3) {
squares.push_back(approx);
}
}
}
}
}
debugSquares(squares, imgeorj,outputFrame);
}
You can try using Hough transform for detecting straight edges and use the those for constructing the square.

Hough lines tansform opencv program breaks

I am trying to use houghlines transform. The function is working well but program breaks after imshow("detected lines",cdst) somewhere in free.c file in free_base function.
please help me out
Here is my code:
#include<opencv\cv.h>
#include<opencv/cxcore.h>
#include<opencv/highgui.h>
#include<opencv2\imgproc\imgproc.hpp>
#include<iostream>
#include<vector>
#include<math.h>
#include <string>
using namespace cv;
using namespace std;
void help()
{
cout << "\nThis program demonstrates line finding with the Hough transform.\n"
"Usage:\n"
"./houghlines <image_name>, Default is pic1.jpg\n" << endl;
}
int houghline(String filename)
{
//const char* filename = argc >= 2 ? argv[1] : "Release\\D.bmp.bmp";
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<Vec2f> lines;
HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 );
float aaa=lines[1][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( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
}
*/
vector<Vec4i> lines;
HoughLinesP(dst, lines, 1, CV_PI/180, 10, 25, 2 );
/*
with the arguments:
dst: Output of the edge detector. It should be a grayscale image (although in fact it is a binary one)
lines: A vector that will store the parameters (x_{start}, y_{start}, x_{end}, y_{end}) of the detected lines
rho : The resolution of the parameter r in pixels. We use 1 pixel.
theta: The resolution of the parameter \theta in radians. We use 1 degree (CV_PI/180)
threshold: The minimum number of intersections to “detect” a line
minLinLength: The minimum number of points that can form a line. Lines with less than this number of points are disregarded.
maxLineGap: The maximum gap between two points to be considered in the same line
*/
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(255,0,0), 1, CV_AA);
imshow("detected lines", cdst);
waitKey();
}
imshow("source", src);
imshow("detected lines", cdst);
}
int main(int argc, char** argv)
{
//for(char alpha='A';alpha<='Z';alpha++)
//String filename="C:\\Users\\Abhinav\\Documents\\Visual Studio 2012\\Projects\\Classes\\Release\\Microsoft Sans Serif\\"+to_string(alpha)+".bmp";
try{houghline("C:\\Users\\Abhinav\\Documents\\Visual Studio 2012\\Projects\\Classes\\Release\\Microsoft Sans Serif\\A.bmp");}
//houghline("C:\\Users\\Abhinav\\Documents\\Visual Studio 2012\\Projects\\Classes\\Release\\Microsoft Sans Serif\\B.bmp");
catch(Exception e){cout<<e.err;}
waitKey();
return 0;
}
It seems that your function "int houghline(String filename)" has no return statement.
Please add "return 0;" at the end of the function and see if it works.

Resources