Yet another about detecting card in a picture. I've managed to pretty much isolate the card in the picture, I have a convex hull that is close and from here I'm stuck.
For the context/constraint, objective:
- Detect a card in a picture
- Plain-ish background (see example)
- Type of card fixed ahead (meaning: we have the width/height ratio)
- One object per picture (for now at least)
Approach I used:
- Downscale
- Gray-scale
- Light Blur
- Canny
- Find contours
- Remove all contours in list with less than 120 points (try/error value)
- Case 1: I have 1 contour: perfect contour of my card: step 9
- Case 2: I have multiple contour
- Convex hull
- Approximate polygon ?
- ???
Step 1, 3 and 6 are mainly to remove noise and small artifacts.
So I'm pretty much stuck at step 9. I've tried on a sample picture:
On the debug picture:
- Green: contours
- Red: convex hull
- Purple/Pink-ish: used approxPolyDp
- Yellow: minAreaRect
(the result image is extracted from the minAreaRect)
So the contour is acceptable, I can probably do a little better by tweaking the parameters from canny or the first blur. But for now this is acceptable, the issue now is, how can I get the the 4 points that will form the "minarea quadrilateral". As you can see, minAreaRect gives a rectangle which is not perfect, and the approxPolyDp is losing too much of the card.
Any clue how I can approach this?
I tried playing with the epsilon value when using approxPolyDp (I used arcLength*0.1
), but nothing.
Another issue with this approach is that is a corner is lost during canny (see example) it'll not work (unless when using minAreaRect). But this can probably be resolved before (with a better pre-processing) or after (since we know the width/height ratio).
Not asking for code here, just ideas how to approach this,
thanks!
Edit: Yves Daoust's solutions:
- Get the 8 points from the convex hull that match the predicate: (maximize x, x+y, y, -x+y, -x, -x-y, -y, x-y)
- From this octagon, take 4 longest sides, get the intersection points
Result:
Edit 2: Using Hough transform (instead of 8 extreme points) gives me better result for all cases where the 4 sides are found. If more than 4 lines are found, probably we have duplicates, so use some maths to try to filter and keep 4 lines. I coded a draft working by using the determinant (close to 0 if parallel) and the point-line distance formula)