Question

I am trying to develop box sorting application in qt and using opencv. I want to measure width and length of box.

Input Image

As shown in image above i want to detect only outermost lines (ie. box edges), which will give me width and length of box, regardless of whatever printed inside the box.

What i tried:

  1. First i tried using Findcontours() and selected contour with max area, but the contour of outer edge is not enclosed(broken somewhere in canny output) many times and hence not get detected as a contour.

  2. Hough line transform gives me too many lines, i dont know how to get only four lines am interested in out of that.

  3. I tried my algorithm as,

    Convert image to gray scale.

    Take one column of image, compare every pixel with next successive pixel of that column, if difference in there value is greater than some threshold(say 100) that pixel belongs to edge, so store it in array. Do this for all columns and it will give upper line of box parallel to x axis.

    Follow the same procedure, but from last column and last row (ie. from bottom to top), it will give lower line parallel to x axis.

    Likewise find lines parallel to y axis as well. Now i have four arrays of points, one for each side.

Now this gives me good results if box is placed in such a way that its sides are exactly parallel to X and Y axis. If box is placed even slightly oriented in some direction, it gives me diagonal lines which is obvious as shown in below image.

Wrong Output

As shown in image below i removed first 10 and last 10 points from all four arrays of points (which are responsible for drawing diagonal lines) and drew the lines, which is not going to work when box is tilted more and also measurements will go wrong.

enter image description here

Now my question is,

Is there any simpler way in opencv to get only outer edges(rectangle) of box and get there dimensions, ignoring anything printed on the box and oriented in whatever direction?

I am not necessarily asking to correct/improve my algorithm, but any suggestions on that also welcome. Sorry for such a big post.

Was it helpful?

Solution

I would suggest the following steps:

1: Make a mask image by using cv::inRange() (documentation) to select the background color. Then use cv::not() to invert this mask. This will give you only the box.

2: If you're not concerned about shadow, depth effects making your measurment inaccurate you can proceed right away with trying to use cv::findContours() again. You select the biggest contour and store it's cv::rotatedRect.

3: This cv::rotatedRect will give you a rotatedRect.size that defines the width en the height of your box in pixels

OTHER TIPS

Since the box is placed in a contrasting background, you should be able to use Otsu thresholding.

  • threshold the image (use Otsu method)
  • filter out any stray pixels that are outside the box region (let's hope you don't get many such pixels and can easily remove them with a median or a morphological filter)
  • find contours
  • combine all contour points and get their convex hull (idea here is to find the convex region that bounds all these contours in the box region regardless of their connectivity)
  • apply a polygon approximation (approxPolyDP) to this convex hull and check if you get a quadrangle
  • if there are no perspective distortions, you should get a rectangle, otherwise you will have to correct it
  • if you get a rectangle, you have its dimensions. You can also find the minimum area rectangle (minAreaRect) of the convexhull, which should directly give you a RotatedRect
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top