1

I am working on a project which will help us to correct the degree of orientation of image.

Here in this code i am detecting a sheet of paper. Steps that i used 1.Apply houghLine transform 2.Detect corner. 3.Applied perspective transform. And with all this I am able to detect sheet of paper but it only works for only one or two images it does not work on all the images and I am not understanding why,

The problem that I think in this code is that it is not able to detect the corners correctly , because of which I am not able to correct the perspective of a image .

it works on this image

sheet

but when i used some other image instead of this then i am not able to do so

sheet2

#include <cv.h>
#include <highgui.h>


using namespace std;
using namespace cv;


Point2f center(0,0);

Point2f computeIntersect(Vec4i a, Vec4i b)
{
    int x1 = a[0], y1 = a[1], x2 = a[2], y2 = a[3], x3 = b[0], y3 = b[1], x4 = b[2], y4 = b[3];
    float denom;

    if (float d = ((float)(x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4)))
    {
        Point2f pt;
        pt.x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
        pt.y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
        return pt;
    }
    else
        return Point2f(-1, -1);
}

void sortCorners(vector<Point2f>& corners, Point2f center)
{
    vector<Point2f> top, bot;

    for (int i = 0; i < corners.size(); i++)
    {
        if (corners[i].y < center.y)
            top.push_back(corners[i]);
        else
            bot.push_back(corners[i]);
    }
    corners.clear();

    if (top.size() == 2 && bot.size() == 2){
        Point2f tl = top[0].x > top[1].x ? top[1] : top[0];
        Point2f tr = top[0].x > top[1].x ? top[0] : top[1];
        Point2f bl = bot[0].x > bot[1].x ? bot[1] : bot[0];
        Point2f br = bot[0].x > bot[1].x ? bot[0] : bot[1];


        corners.push_back(tl);
        corners.push_back(tr);
        corners.push_back(br);
        corners.push_back(bl);
    }
}

int main()
{
    Mat src,cann,hsv;
    src = imread("C:\\im.jpg",WINDOW_AUTOSIZE);

    if (src.empty())
        return -1;

    imshow("original",src);

    blur(src, src, Size(3, 3));
    Canny(src, cann, 50, 200, 3);
    cvtColor(cann, hsv, CV_GRAY2BGR);

    vector<Vec4i> lines;
    HoughLinesP(cann, lines, 1, CV_PI/180, 70, 30, 10);
    for( size_t i = 0; i < lines.size(); i++ )
    {
        Vec4i l = lines[i];
        line( hsv, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 2, CV_AA);
    } 

    // Expand the lines
    for (int i = 0; i < lines.size(); i++)
    {
        Vec4i v = lines[i];
        lines[i][0] = 0;
        lines[i][1] = ((float)v[1] - v[3]) / (v[0] - v[2]) * -v[0] + v[1]; 
        lines[i][2] = src.cols; 
        lines[i][3] = ((float)v[1] - v[3]) / (v[0] - v[2]) * (src.cols - v[2]) + v[3];
    }

    vector<Point2f> corners;
    for (int i = 0; i < lines.size(); i++)
    {
        for (int j = i+1; j < lines.size(); j++)
        {
            Point2f pt = computeIntersect(lines[i], lines[j]);
            if (pt.x >= 0 && pt.y >= 0)
                corners.push_back(pt);
        }
    }

    vector<Point2f> approx;
    approxPolyDP(Mat(corners), approx, arcLength(Mat(corners), true) * 0.02, true);

    //if (approx.size() != 4)
//  {
    //  cout << "The object is not quadrilateral!" << endl;
        //return -1;
    //}



    // Get mass center
    for (int i = 0; i < corners.size(); i++)
        center += corners[i];

    center *= (1. / corners.size());

    sortCorners(corners, center);
    if (corners.size() == 0)
    {
        cout << "The corners were not sorted correctly!" << endl;
        return -1;
    }

    Mat dst = src.clone();

    // Draw lines
    for (int i = 0; i < lines.size(); i++)
    {
        Vec4i v = lines[i];
        line(dst, Point(v[0], v[1]), Point(v[2], v[3]), CV_RGB(0,255,0));
    }

    // Draw corner points
    circle(dst, corners[0], 3, CV_RGB(255,0,0), 2);
    circle(dst, corners[1], 3, CV_RGB(0,255,0), 2);
    circle(dst, corners[2], 3, CV_RGB(0,0,255), 2);
    circle(dst, corners[3], 3, CV_RGB(255,255,255), 2);
    // Draw mass center
    circle(dst, center, 3, CV_RGB(255,255,0), 2);

    Mat quad = Mat::zeros(300, 220, CV_8UC3);

    vector<Point2f> quad_pts;
    quad_pts.push_back(Point2f(0, 0));
    quad_pts.push_back(Point2f(quad.cols, 0));
    quad_pts.push_back(Point2f(quad.cols, quad.rows));
    quad_pts.push_back(Point2f(0, quad.rows));

    Mat transmtx = getPerspectiveTransform(corners, quad_pts);
    warpPerspective(src, quad, transmtx, quad.size());

    imshow("blurr",src);
    imshow("canney",cann);
    imshow("hough",hsv);
    imshow("image", dst);
    imshow("quadrilateral", quad);

    waitKey(0);
    return 0;
}

please please help me this i am really get stuck with this .

Chandan
  • 61
  • 1
  • 7
  • 2
    Possible duplicate of [Applying perspective transform correct the degree of sheet of paper](http://stackoverflow.com/questions/42183766/applying-perspective-transform-correct-the-degree-of-sheet-of-paper) – beaker Feb 12 '17 at 16:24
  • Will the paper always be white and/or lighter than the background? And will the paper always be roughly aligned with the axes of the image? Do you have to use OpenCV, or can you write custom algorithms? You may be seeing a problem with barrel distortion (https://en.wikipedia.org/wiki/Distortion_(optics)) and/or wrinkly paper, in which case edges won't be straight. That'd be a problem for Hough. In simpler cases that can be resolved by customizing the accumulator to allow for rough or slightly curved lines. Depending on your full image set, there will be other ways to address the problem. – Rethunk Feb 13 '17 at 02:45
  • Paper will always white for ideal case (which is right now) , no paper is with different alignment and I implementing this in opencv – Chandan Feb 13 '17 at 17:11

1 Answers1

0

Your algorithm assumes that HoughLinesP function will always detect only 4 lines and that each one will lie on a different edge of the paper. However, this assumption is wrong. In your particular case, when you work with the second image, it returns 5 lines when you work on the second image. Click to see the detected lines (marked by non-gray colours).

Quick fix

I changed the value of 6th HoughLinesP argument (minLineThreshold parameter) to 70. After that, only four lines were detected in the image, but another bug surfaced; 5 corners were detected instead of 4. The reason? Two of the opposite edges were not parallel and they intersected far outside the image area. This condition was causing the problem:

if (pt.x >= 0 && pt.y >= 0)
            corners.push_back(pt);

It is not enough to check whether corners coordinates are non-negative. Instead, you have to make sure that the corners are within certain boundaries that make sense; in your case these could be boundaries of the image.

if (pt.x >= 0 && pt.y >= 0 && pt.x <src.cols && pt.y < src.rows)
            corners.push_back(pt);

After changing threshold and fixing the condition, I obtained this result: (Click to see an image)

Warning

As you can see, yet another problem surfaced - the corners are not detected as accurately as they could be. You can use information provided by canny edges to your advantage here. But I do not want to venture out of the scope of your question here, so I'll stop.

I named my solution as a "quick fix" because it only solves one particular case. If you want more general solution and if you want to keep using your algorithm, you will have to compute a reasonable threshold estimate every time before you use HoughLineP.

Nejc
  • 927
  • 6
  • 15