1

I am new in openCV, I already detect edge of paper sheet but my result image is blurred after draw lines on edge, How I can draw lines on edges of paper sheet so my image quality remain unaffected.

what I am Missing..

My code is below.

Many thanks.

enter image description here

-(void)forOpenCV
{
   if( imageView.image != nil )
   {

      cv::Mat greyMat=[self cvMatFromUIImage:imageView.image];
      vector<vector<cv::Point> > squares;

      cv::Mat img= [self debugSquares: squares: greyMat ];


      imageView.image =[self UIImageFromCVMat: img];

   }

}


- (cv::Mat) debugSquares: (std::vector<std::vector<cv::Point> >) squares : (cv::Mat &)image
{
NSLog(@"%lu",squares.size());

// blur will enhance edge detection

Mat blurred(image);
medianBlur(image, blurred, 9);

Mat gray0(image.size(), CV_8U), gray;
vector<vector<cv::Point> > contours;

// find squares in every color plane of the image
for (int c = 0; c < 3; c++)
{
    int ch[] = {c, 0};
    mixChannels(&image, 1, &gray0, 1, ch, 1);

    // try several threshold levels
    const int threshold_level = 2;
    for (int l = 0; l < threshold_level; l++)
    {
        // Use Canny instead of zero threshold level!
        // Canny helps to catch squares with gradient shading
        if (l == 0)
        {
            Canny(gray0, gray, 10, 20, 3); //

            // Dilate helps to remove potential holes between edge segments
            dilate(gray, gray, Mat(), cv::Point(-1,-1));
        }
        else
        {
            gray = gray0 >= (l+1) * 255 / threshold_level;
        }

        // Find contours and store them in a list
        findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

        // Test contours
        vector<cv::Point> approx;
        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);

            // Note: absolute value of an area is used because
            // area may be positive or negative - in accordance with the
            // contour orientation
            if (approx.size() == 4 &&
                fabs(contourArea(Mat(approx))) > 1000 &&
                isContourConvex(Mat(approx)))
            {
                double maxCosine = 0;

                for (int j = 2; j < 5; j++)
                {
                    double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
                    maxCosine = MAX(maxCosine, cosine);
                }

                if (maxCosine < 0.3)
                    squares.push_back(approx);
            }
        }
    }
}

NSLog(@"%lu",squares.size());


for( size_t i = 0; i < squares.size(); i++ )
{


    cv:: Rect rectangle = boundingRect(Mat(squares[i]));
    if(i==squares.size()-1)////Detecting Rectangle here
    {
        const cv::Point* p = &squares[i][0];


        int n = (int)squares[i].size();

         NSLog(@"%d",n);



        line(image, cv::Point(507,418), cv::Point(507+1776,418+1372), Scalar(255,0,0),2,8);

        polylines(image, &p, &n, 1, true, Scalar(255,255,0), 5, CV_AA);



        fx1=rectangle.x;
        fy1=rectangle.y;
        fx2=rectangle.x+rectangle.width;
        fy2=rectangle.y+rectangle.height;


        line(image, cv::Point(fx1,fy1), cv::Point(fx2,fy2), Scalar(0,0,255),2,8);


    }



}


return image;
}
QueueOverFlow
  • 1,336
  • 5
  • 27
  • 48
  • Hi @QueueOverFlow, I am referring your opencv code to do the thing similar to what you've did. I've a doubt in it. What does the function angle(arg1, arg2, arg3) refer to in your above code? Can you please help me? – Ananth Dec 20 '12 at 08:11
  • can you add the angle function? – Dubon Ya'ar Oct 18 '16 at 08:11

2 Answers2

1

Instead of

Mat blurred(image);

you need to do

Mat blurred = image.clone();

Because the first line does not copy the image, but just creates a second pointer to the same data. When you blurr the image, you are also changing the original. What you need to do instead is, to create a real copy of the actual data and operate on this copy.

The OpenCV reference states:

by using a copy constructor or assignment operator, where on the right side it can be a matrix or expression, see below. Again, as noted in the introduction, matrix assignment is O(1) operation because it only copies the header and increases the reference counter.

Mat::clone() method can be used to get a full (a.k.a. deep) copy of the matrix when you need it.

sietschie
  • 7,425
  • 3
  • 33
  • 54
  • +1 for you, image quality is good now, but now not detect the edge of paper, now draw rectangle on complete view – QueueOverFlow Nov 21 '12 at 13:51
  • you have to make sure that you are using the blurred image for contour extraction. For example `mixChannels(&image, 1, &gray0, 1, ch, 1);` should probably be `mixChannels(&blurred, 1, &gray0, 1, ch, 1);`. Does this fix your problem? – sietschie Nov 22 '12 at 07:50
  • thanks for your reply, but i already modify most of my code ,my this problem is 90 % solved. I wants to know how We can crop that boundary area? please look on my another question..http://stackoverflow.com/questions/13098073/adjust-corners-and-crop-the-image-opencv – QueueOverFlow Nov 22 '12 at 09:10
1

The first problem is easily solved by doing the entire processing on a copy of the original image. That way, after you get all the points of the square you can draw the lines on the original image and it will not be blurred.

The second problem, which is cropping, can be solved by defining a ROI (region of interested) in the original image and then copying it to a new Mat. I've demonstrated that in this answer:

// Setup a Region Of Interest
cv::Rect roi;
roi.x = 50
roi.y = 10
roi.width = 400;
roi.height = 450;

// Crop the original image to the area defined by ROI
cv::Mat crop = original_image(roi);

cv::imwrite("cropped.png", crop);
Community
  • 1
  • 1
karlphillip
  • 92,053
  • 36
  • 243
  • 426