Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Robust edge detection OpenCV

I have been using this method to find a card and crop it out of the image:

void findCardAndCrop(Mat& bw,Mat& outerBox)
{
    // Remove noise
    GaussianBlur(bw, bw, cv::Size(11,11), 0);

    adaptiveThreshold(bw, outerBox, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 101, 16);
    bitwise_not(outerBox, outerBox);
    Mat kernel = (Mat_<uchar>(3,3) << 0,1,0,1,1,1,0,1,0);
    dilate(outerBox, outerBox, kernel);

    //int count=0;
    int max=-1;
    cv::Point maxPt;

    for(int y=0;y<outerBox.size().height;y++)
    {
        uchar *row = outerBox.ptr(y);
        for(int x=0;x<outerBox.size().width;x++)
        {
            if(row[x]>=128)
            {
                int area = floodFill(outerBox, cv::Point(x,y), 64);

                if(area>max)
                {
                    maxPt = cv::Point(x,y);
                    max = area;
                }
            }
        }
    }
    floodFill(outerBox, maxPt, CV_RGB(255,255,255));

    for(int y=0;y<outerBox.size().height;y++)
    {
        uchar *row = outerBox.ptr(y);
        for(int x=0;x<outerBox.size().width;x++)
        {
            if(row[x]==64 && x!=maxPt.x && y!=maxPt.y)
            {
                int area = floodFill(outerBox, cv::Point(x,y), CV_RGB(0,0,0));
            }
        }
    }

    erode(outerBox, outerBox, kernel);

    vector<Vec2f> lines;
    HoughLines(outerBox, lines, 1, CV_PI/180, 1200);
    mergeRelatedLines(&lines, outerBox);

    for(int i=0;i<lines.size();i++)
    {
        drawLine(lines[i], outerBox, CV_RGB(0,0,128));
    }

    Vec2f topEdge = Vec2f(1000,1000);   //double topYIntercept=100000;//, topXIntercept=0;
    Vec2f bottomEdge = Vec2f(-1000,-1000);      //double bottomYIntercept=0;//, bottomXIntercept=0;
    Vec2f leftEdge = Vec2f(1000,1000);  double leftXIntercept=100000;//, leftYIntercept=0;
    Vec2f rightEdge = Vec2f(-1000,-1000);       double rightXIntercept=0;//, rightYIntercept=0;
    for(int i=0;i<lines.size();i++)
    {
        Vec2f current = lines[i];

        float p=current[0];
        float theta=current[1];

        if(p==0 && theta==-100)
            continue;

        double xIntercept, yIntercept;
        xIntercept = p/cos(theta);
        yIntercept = p/(cos(theta)*sin(theta));

        if(theta>CV_PI*80/180 && theta<CV_PI*100/180)
        {
            if(p<topEdge[0])
                topEdge = current;

            if(p>bottomEdge[0])
                bottomEdge = current;

            //printf("X: %f, Y: %f\n", xIntercept, yIntercept);

        }
        else if(theta<CV_PI*10/180 || theta>CV_PI*170/180)
        {
            /*if(p<leftEdge[0])
             leftEdge = current;

             if(p>rightEdge[0])
             rightEdge = current;*/

            if(xIntercept>rightXIntercept)
            {
                rightEdge = current;
                rightXIntercept = xIntercept;
            }
            else if(xIntercept<=leftXIntercept)
            {
                leftEdge = current;
                leftXIntercept = xIntercept;
            }
        }
    }


    drawLine(topEdge, outerBox, CV_RGB(0,0,0));
    drawLine(bottomEdge, outerBox, CV_RGB(0,0,0));
    drawLine(leftEdge, outerBox, CV_RGB(0,0,0));
    drawLine(rightEdge, outerBox, CV_RGB(0,0,0));

    cv::Point left1, left2, right1, right2, bottom1, bottom2, top1, top2;

    int height=outerBox.size().height;
    int width=outerBox.size().width;

    if(leftEdge[1]!=0)
    {
        left1.x=0;      left1.y=leftEdge[0]/sin(leftEdge[1]);
        left2.x=width;  left2.y=-left2.x/tan(leftEdge[1]) + left1.y;
    }
    else
    {
        left1.y=0;      left1.x=leftEdge[0]/cos(leftEdge[1]);
        left2.y=height; left2.x=left1.x - height*tan(leftEdge[1]);
    }

    if(rightEdge[1]!=0)
    {
        right1.x=0;     right1.y=rightEdge[0]/sin(rightEdge[1]);
        right2.x=width; right2.y=-right2.x/tan(rightEdge[1]) + right1.y;
    }
    else
    {
        right1.y=0;     right1.x=rightEdge[0]/cos(rightEdge[1]);
        right2.y=height;    right2.x=right1.x - height*tan(rightEdge[1]);
    }

    bottom1.x=0;    bottom1.y=bottomEdge[0]/sin(bottomEdge[1]);
    bottom2.x=width;bottom2.y=-bottom2.x/tan(bottomEdge[1]) + bottom1.y;

    top1.x=0;       top1.y=topEdge[0]/sin(topEdge[1]);
    top2.x=width;   top2.y=-top2.x/tan(topEdge[1]) + top1.y;

    // Next, we find the intersection of  these four lines
    double leftA = left2.y-left1.y;
    double leftB = left1.x-left2.x;
    double leftC = leftA*left1.x + leftB*left1.y;

    double rightA = right2.y-right1.y;
    double rightB = right1.x-right2.x;
    double rightC = rightA*right1.x + rightB*right1.y;

    double topA = top2.y-top1.y;
    double topB = top1.x-top2.x;
    double topC = topA*top1.x + topB*top1.y;

    double bottomA = bottom2.y-bottom1.y;
    double bottomB = bottom1.x-bottom2.x;
    double bottomC = bottomA*bottom1.x + bottomB*bottom1.y;

    // Intersection of left and top
    double detTopLeft = leftA*topB - leftB*topA;
    CvPoint ptTopLeft = cvPoint((topB*leftC - leftB*topC)/detTopLeft, (leftA*topC - topA*leftC)/detTopLeft);

    // Intersection of top and right
    double detTopRight = rightA*topB - rightB*topA;
    CvPoint ptTopRight = cvPoint((topB*rightC-rightB*topC)/detTopRight, (rightA*topC-topA*rightC)/detTopRight);

    // Intersection of right and bottom
    double detBottomRight = rightA*bottomB - rightB*bottomA;
    CvPoint ptBottomRight = cvPoint((bottomB*rightC-rightB*bottomC)/detBottomRight, (rightA*bottomC-bottomA*rightC)/detBottomRight);

    // Intersection of bottom and left
    double detBottomLeft = leftA*bottomB-leftB*bottomA;
    CvPoint ptBottomLeft = cvPoint((bottomB*leftC-leftB*bottomC)/detBottomLeft, (leftA*bottomC-bottomA*leftC)/detBottomLeft);

    cv::line(outerBox, ptTopRight, ptTopRight, CV_RGB(255,0,0), 10);
    cv::line(outerBox, ptTopLeft, ptTopLeft, CV_RGB(255,0,0), 10);
    cv::line(outerBox, ptBottomRight, ptBottomRight, CV_RGB(255,0,0), 10);
    cv::line(outerBox, ptBottomLeft, ptBottomLeft, CV_RGB(255,0,0), 10);

    // Correct the perspective transform
    int maxLength = (ptBottomLeft.x-ptBottomRight.x)*(ptBottomLeft.x-ptBottomRight.x) + (ptBottomLeft.y-ptBottomRight.y)*(ptBottomLeft.y-ptBottomRight.y);
    int temp = (ptTopRight.x-ptBottomRight.x)*(ptTopRight.x-ptBottomRight.x) + (ptTopRight.y-ptBottomRight.y)*(ptTopRight.y-ptBottomRight.y);
    if(temp>maxLength) maxLength = temp;

    temp = (ptTopRight.x-ptTopLeft.x)*(ptTopRight.x-ptTopLeft.x) + (ptTopRight.y-ptTopLeft.y)*(ptTopRight.y-ptTopLeft.y);
    if(temp>maxLength) maxLength = temp;

    temp = (ptBottomLeft.x-ptTopLeft.x)*(ptBottomLeft.x-ptTopLeft.x) + (ptBottomLeft.y-ptTopLeft.y)*(ptBottomLeft.y-ptTopLeft.y);
    if(temp>maxLength) maxLength = temp;

    maxLength = sqrt((double)maxLength);


    Point2f src[4], dst[4];
    src[0] = ptTopLeft;         dst[0] = Point2f(0,0);
    src[1] = ptTopRight;        dst[1] = Point2f(maxLength-1, 0);
    src[2] = ptBottomRight;     dst[2] = Point2f(maxLength-1, maxLength-1);
    src[3] = ptBottomLeft;      dst[3] = Point2f(0, maxLength-1);

    Mat undistorted = Mat(cv::Size(maxLength, maxLength), CV_8UC1);
    cv::warpPerspective(bw.clone(), outerBox, cv::getPerspectiveTransform(src, dst), cv::Size(maxLength, maxLength));

}

void drawLine(Vec2f line, Mat &img, Scalar rgb = CV_RGB(0,0,255))
{
    if(line[1]!=0)
    {
        float m = -1/tan(line[1]);
        float c = line[0]/sin(line[1]);

        cv::line(img, cv::Point(0, c), cv::Point(img.size().width, m*img.size().width+c), rgb);
    }
    else
    {
        cv::line(img, cv::Point(line[0], 0), cv::Point(line[0], img.size().height), rgb);
    }
}

Where mergeRelatedLines

void mergeRelatedLines(vector<Vec2f> *lines, Mat &img)
{
    vector<Vec2f>::iterator current;
    vector<Vec4i> points(lines->size());
    for(current=lines->begin();current!=lines->end();current++)
    {
        if((*current)[0]==0 && (*current)[1]==-100)
            continue;

        float p1 = (*current)[0];
        float theta1 = (*current)[1];

        cv::Point pt1current, pt2current;
        if(theta1>CV_PI*45/180 && theta1<CV_PI*135/180)
        {
            pt1current.x=0;
            pt1current.y = p1/sin(theta1);

            pt2current.x=img.size().width;
            pt2current.y=-pt2current.x/tan(theta1) + p1/sin(theta1);
        }
        else
        {
            pt1current.y=0;
            pt1current.x=p1/cos(theta1);

            pt2current.y=img.size().height;
            pt2current.x=-pt2current.y/tan(theta1) + p1/cos(theta1);
        }

        vector<Vec2f>::iterator pos;
        for(pos=lines->begin();pos!=lines->end();pos++)
        {
            if(*current==*pos)
                continue;

            if(fabs((*pos)[0]-(*current)[0])<20 && fabs((*pos)[1]-(*current)[1])<CV_PI*10/180)
            {
                float p = (*pos)[0];
                float theta = (*pos)[1];

                cv::Point pt1, pt2;
                if((*pos)[1]>CV_PI*45/180 && (*pos)[1]<CV_PI*135/180)
                {
                    pt1.x=0;
                    pt1.y = p/sin(theta);

                    pt2.x=img.size().width;
                    pt2.y=-pt2.x/tan(theta) + p/sin(theta);
                }
                else
                {
                    pt1.y=0;
                    pt1.x=p/cos(theta);

                    pt2.y=img.size().height;
                    pt2.x=-pt2.y/tan(theta) + p/cos(theta);
                }

                if(((double)(pt1.x-pt1current.x)*(pt1.x-pt1current.x) + (pt1.y-pt1current.y)*(pt1.y-pt1current.y)<64*64) && ((double)(pt2.x-pt2current.x)*(pt2.x-pt2current.x) + (pt2.y-pt2current.y)*(pt2.y-pt2current.y)<64*64))
                {
                    //printf("Merging\n");
                    // Merge the two
                    (*current)[0] = ((*current)[0]+(*pos)[0])/2;
                    (*current)[1] = ((*current)[1]+(*pos)[1])/2;

                    (*pos)[0]=0;
                    (*pos)[1]=-100;
                    //lines->erase(pos);
                }
            }
        }
    }

    //return lines;
}

And drawLine

void drawLine(Vec2f line, Mat &img, Scalar rgb = CV_RGB(0,0,255))
{
    if(line[1]!=0)
    {
        float m = -1/tan(line[1]);
        float c = line[0]/sin(line[1]);

        cv::line(img, cv::Point(0, c), cv::Point(img.size().width, m*img.size().width+c), rgb);
    }
    else
    {
        cv::line(img, cv::Point(line[0], 0), cv::Point(line[0], img.size().height), rgb);
    }
}

When given this image it detects no card:

enter image description here

I tested this out on a iPhone app and it successfully detected the card, can someone explain how I can successfully detect this card and other strangely designed cards? If the border of the card is not consistent I cannot find the card any help is greatly appreciated!

Robust edge detection OpenCV

I have been using this method to find a card and crop it out of the image:

void findCardAndCrop(Mat& bw,Mat& outerBox)
{
    // Remove noise
    GaussianBlur(bw, bw, cv::Size(11,11), 0);

    adaptiveThreshold(bw, outerBox, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 101, 16);
    bitwise_not(outerBox, outerBox);
    Mat kernel = (Mat_<uchar>(3,3) << 0,1,0,1,1,1,0,1,0);
    dilate(outerBox, outerBox, kernel);

    //int count=0;
    int max=-1;
    cv::Point maxPt;

    for(int y=0;y<outerBox.size().height;y++)
    {
        uchar *row = outerBox.ptr(y);
        for(int x=0;x<outerBox.size().width;x++)
        {
            if(row[x]>=128)
            {
                int area = floodFill(outerBox, cv::Point(x,y), 64);

                if(area>max)
                {
                    maxPt = cv::Point(x,y);
                    max = area;
                }
            }
        }
    }
    floodFill(outerBox, maxPt, CV_RGB(255,255,255));

    for(int y=0;y<outerBox.size().height;y++)
    {
        uchar *row = outerBox.ptr(y);
        for(int x=0;x<outerBox.size().width;x++)
        {
            if(row[x]==64 && x!=maxPt.x && y!=maxPt.y)
            {
                int area = floodFill(outerBox, cv::Point(x,y), CV_RGB(0,0,0));
            }
        }
    }

    erode(outerBox, outerBox, kernel);

    vector<Vec2f> lines;
    HoughLines(outerBox, lines, 1, CV_PI/180, 1200);
    mergeRelatedLines(&lines, outerBox);

    for(int i=0;i<lines.size();i++)
    {
        drawLine(lines[i], outerBox, CV_RGB(0,0,128));
    }

    Vec2f topEdge = Vec2f(1000,1000);   //double topYIntercept=100000;//, topXIntercept=0;
    Vec2f bottomEdge = Vec2f(-1000,-1000);      //double bottomYIntercept=0;//, bottomXIntercept=0;
    Vec2f leftEdge = Vec2f(1000,1000);  double leftXIntercept=100000;//, leftYIntercept=0;
    Vec2f rightEdge = Vec2f(-1000,-1000);       double rightXIntercept=0;//, rightYIntercept=0;
    for(int i=0;i<lines.size();i++)
    {
        Vec2f current = lines[i];

        float p=current[0];
        float theta=current[1];

        if(p==0 && theta==-100)
            continue;

        double xIntercept, yIntercept;
        xIntercept = p/cos(theta);
        yIntercept = p/(cos(theta)*sin(theta));

        if(theta>CV_PI*80/180 && theta<CV_PI*100/180)
        {
            if(p<topEdge[0])
                topEdge = current;

            if(p>bottomEdge[0])
                bottomEdge = current;

            //printf("X: %f, Y: %f\n", xIntercept, yIntercept);

        }
        else if(theta<CV_PI*10/180 || theta>CV_PI*170/180)
        {
            /*if(p<leftEdge[0])
             leftEdge = current;

             if(p>rightEdge[0])
             rightEdge = current;*/

            if(xIntercept>rightXIntercept)
            {
                rightEdge = current;
                rightXIntercept = xIntercept;
            }
            else if(xIntercept<=leftXIntercept)
            {
                leftEdge = current;
                leftXIntercept = xIntercept;
            }
        }
    }


    drawLine(topEdge, outerBox, CV_RGB(0,0,0));
    drawLine(bottomEdge, outerBox, CV_RGB(0,0,0));
    drawLine(leftEdge, outerBox, CV_RGB(0,0,0));
    drawLine(rightEdge, outerBox, CV_RGB(0,0,0));

    cv::Point left1, left2, right1, right2, bottom1, bottom2, top1, top2;

    int height=outerBox.size().height;
    int width=outerBox.size().width;

    if(leftEdge[1]!=0)
    {
        left1.x=0;      left1.y=leftEdge[0]/sin(leftEdge[1]);
        left2.x=width;  left2.y=-left2.x/tan(leftEdge[1]) + left1.y;
    }
    else
    {
        left1.y=0;      left1.x=leftEdge[0]/cos(leftEdge[1]);
        left2.y=height; left2.x=left1.x - height*tan(leftEdge[1]);
    }

    if(rightEdge[1]!=0)
    {
        right1.x=0;     right1.y=rightEdge[0]/sin(rightEdge[1]);
        right2.x=width; right2.y=-right2.x/tan(rightEdge[1]) + right1.y;
    }
    else
    {
        right1.y=0;     right1.x=rightEdge[0]/cos(rightEdge[1]);
        right2.y=height;    right2.x=right1.x - height*tan(rightEdge[1]);
    }

    bottom1.x=0;    bottom1.y=bottomEdge[0]/sin(bottomEdge[1]);
    bottom2.x=width;bottom2.y=-bottom2.x/tan(bottomEdge[1]) + bottom1.y;

    top1.x=0;       top1.y=topEdge[0]/sin(topEdge[1]);
    top2.x=width;   top2.y=-top2.x/tan(topEdge[1]) + top1.y;

    // Next, we find the intersection of  these four lines
    double leftA = left2.y-left1.y;
    double leftB = left1.x-left2.x;
    double leftC = leftA*left1.x + leftB*left1.y;

    double rightA = right2.y-right1.y;
    double rightB = right1.x-right2.x;
    double rightC = rightA*right1.x + rightB*right1.y;

    double topA = top2.y-top1.y;
    double topB = top1.x-top2.x;
    double topC = topA*top1.x + topB*top1.y;

    double bottomA = bottom2.y-bottom1.y;
    double bottomB = bottom1.x-bottom2.x;
    double bottomC = bottomA*bottom1.x + bottomB*bottom1.y;

    // Intersection of left and top
    double detTopLeft = leftA*topB - leftB*topA;
    CvPoint ptTopLeft = cvPoint((topB*leftC - leftB*topC)/detTopLeft, (leftA*topC - topA*leftC)/detTopLeft);

    // Intersection of top and right
    double detTopRight = rightA*topB - rightB*topA;
    CvPoint ptTopRight = cvPoint((topB*rightC-rightB*topC)/detTopRight, (rightA*topC-topA*rightC)/detTopRight);

    // Intersection of right and bottom
    double detBottomRight = rightA*bottomB - rightB*bottomA;
    CvPoint ptBottomRight = cvPoint((bottomB*rightC-rightB*bottomC)/detBottomRight, (rightA*bottomC-bottomA*rightC)/detBottomRight);

    // Intersection of bottom and left
    double detBottomLeft = leftA*bottomB-leftB*bottomA;
    CvPoint ptBottomLeft = cvPoint((bottomB*leftC-leftB*bottomC)/detBottomLeft, (leftA*bottomC-bottomA*leftC)/detBottomLeft);

    cv::line(outerBox, ptTopRight, ptTopRight, CV_RGB(255,0,0), 10);
    cv::line(outerBox, ptTopLeft, ptTopLeft, CV_RGB(255,0,0), 10);
    cv::line(outerBox, ptBottomRight, ptBottomRight, CV_RGB(255,0,0), 10);
    cv::line(outerBox, ptBottomLeft, ptBottomLeft, CV_RGB(255,0,0), 10);

    // Correct the perspective transform
    int maxLength = (ptBottomLeft.x-ptBottomRight.x)*(ptBottomLeft.x-ptBottomRight.x) + (ptBottomLeft.y-ptBottomRight.y)*(ptBottomLeft.y-ptBottomRight.y);
    int temp = (ptTopRight.x-ptBottomRight.x)*(ptTopRight.x-ptBottomRight.x) + (ptTopRight.y-ptBottomRight.y)*(ptTopRight.y-ptBottomRight.y);
    if(temp>maxLength) maxLength = temp;

    temp = (ptTopRight.x-ptTopLeft.x)*(ptTopRight.x-ptTopLeft.x) + (ptTopRight.y-ptTopLeft.y)*(ptTopRight.y-ptTopLeft.y);
    if(temp>maxLength) maxLength = temp;

    temp = (ptBottomLeft.x-ptTopLeft.x)*(ptBottomLeft.x-ptTopLeft.x) + (ptBottomLeft.y-ptTopLeft.y)*(ptBottomLeft.y-ptTopLeft.y);
    if(temp>maxLength) maxLength = temp;

    maxLength = sqrt((double)maxLength);


    Point2f src[4], dst[4];
    src[0] = ptTopLeft;         dst[0] = Point2f(0,0);
    src[1] = ptTopRight;        dst[1] = Point2f(maxLength-1, 0);
    src[2] = ptBottomRight;     dst[2] = Point2f(maxLength-1, maxLength-1);
    src[3] = ptBottomLeft;      dst[3] = Point2f(0, maxLength-1);

    Mat undistorted = Mat(cv::Size(maxLength, maxLength), CV_8UC1);
    cv::warpPerspective(bw.clone(), outerBox, cv::getPerspectiveTransform(src, dst), cv::Size(maxLength, maxLength));

}

void drawLine(Vec2f line, Mat &img, Scalar rgb = CV_RGB(0,0,255))
{
    if(line[1]!=0)
    {
        float m = -1/tan(line[1]);
        float c = line[0]/sin(line[1]);

        cv::line(img, cv::Point(0, c), cv::Point(img.size().width, m*img.size().width+c), rgb);
    }
    else
    {
        cv::line(img, cv::Point(line[0], 0), cv::Point(line[0], img.size().height), rgb);
    }
}

Where mergeRelatedLines

void mergeRelatedLines(vector<Vec2f> *lines, Mat &img)
{
    vector<Vec2f>::iterator current;
    vector<Vec4i> points(lines->size());
    for(current=lines->begin();current!=lines->end();current++)
    {
        if((*current)[0]==0 && (*current)[1]==-100)
            continue;

        float p1 = (*current)[0];
        float theta1 = (*current)[1];

        cv::Point pt1current, pt2current;
        if(theta1>CV_PI*45/180 && theta1<CV_PI*135/180)
        {
            pt1current.x=0;
            pt1current.y = p1/sin(theta1);

            pt2current.x=img.size().width;
            pt2current.y=-pt2current.x/tan(theta1) + p1/sin(theta1);
        }
        else
        {
            pt1current.y=0;
            pt1current.x=p1/cos(theta1);

            pt2current.y=img.size().height;
            pt2current.x=-pt2current.y/tan(theta1) + p1/cos(theta1);
        }

        vector<Vec2f>::iterator pos;
        for(pos=lines->begin();pos!=lines->end();pos++)
        {
            if(*current==*pos)
                continue;

            if(fabs((*pos)[0]-(*current)[0])<20 && fabs((*pos)[1]-(*current)[1])<CV_PI*10/180)
            {
                float p = (*pos)[0];
                float theta = (*pos)[1];

                cv::Point pt1, pt2;
                if((*pos)[1]>CV_PI*45/180 && (*pos)[1]<CV_PI*135/180)
                {
                    pt1.x=0;
                    pt1.y = p/sin(theta);

                    pt2.x=img.size().width;
                    pt2.y=-pt2.x/tan(theta) + p/sin(theta);
                }
                else
                {
                    pt1.y=0;
                    pt1.x=p/cos(theta);

                    pt2.y=img.size().height;
                    pt2.x=-pt2.y/tan(theta) + p/cos(theta);
                }

                if(((double)(pt1.x-pt1current.x)*(pt1.x-pt1current.x) + (pt1.y-pt1current.y)*(pt1.y-pt1current.y)<64*64) && ((double)(pt2.x-pt2current.x)*(pt2.x-pt2current.x) + (pt2.y-pt2current.y)*(pt2.y-pt2current.y)<64*64))
                {
                    //printf("Merging\n");
                    // Merge the two
                    (*current)[0] = ((*current)[0]+(*pos)[0])/2;
                    (*current)[1] = ((*current)[1]+(*pos)[1])/2;

                    (*pos)[0]=0;
                    (*pos)[1]=-100;
                    //lines->erase(pos);
                }
            }
        }
    }

    //return lines;
}

And drawLine

void drawLine(Vec2f line, Mat &img, Scalar rgb = CV_RGB(0,0,255))
{
    if(line[1]!=0)
    {
        float m = -1/tan(line[1]);
        float c = line[0]/sin(line[1]);

        cv::line(img, cv::Point(0, c), cv::Point(img.size().width, m*img.size().width+c), rgb);
    }
    else
    {
        cv::line(img, cv::Point(line[0], 0), cv::Point(line[0], img.size().height), rgb);
    }
}

When given this image it detects no card:

enter image description here

I tested this out on a iPhone app and it successfully detected the card, can someone explain how I can successfully detect this card and other strangely designed cards? If the border of the card is not consistent I cannot find the card any help is greatly appreciated!