Biggest Rectangle within one color - c++

I struggle to find a solution to the following problem :
I used opencv to mark all connected white pixels with a unique label.
Now i got a group of those elements.
Those objects often are 90% rectangular but most of the time contain some extra lines and stuff.
Im searching for a algorithm which does thr following :
-get biggest Rectangle out of image(within the same label)
- fast performance
-maybe even filter, larget rectangle which contains at least xx% Pixels with the same label
Maybe someone can help me
Thanks a lot
Edit: Example Pictures(in this case fo licence plate location):
my desired output of the algorithm would be the rectangle of the plate(and of curse all other rectangles in the image, im gonna filter them later)
Important the rectangles may be rotated !

My suggestion
make sure to fill small holes either by blob analysis or mathematical morphology;
compute the distance map in the white areas;
binarize the distance map with a threshold equal to the half plate height.
The rectangles will appear as line segments long as the plate width minus the plate height. You may locate them by fitting rotated rectangular bounding boxes; they must have a large aspect ratio.

Related

Pack pixels in 1bit/bw/binary image in boxes

I need an algorithm that, from a 1bit 2D image (a 2D matrix of mixed 1s and 0s) returns me rectangles (with the x,y coordinates of each corner) that packs the pixels that are equal to zero, using the least amount of boxes.
So for an image like
0000000
1111111
1111111
1111110
1111100
0000000
It would return something like
Rectangle 1 ((0,0),(0,1),(7,0),(7,1))
Rectangle 2 ((6,3),(7,3),(7,4),(6,4))
Rectangle 3 ((5,4),(7,4),(7,6),(5,6))
Rectangle 4 ((0,5),(0,6),(7,6),(7,5))
I feel this algorithm exists, but I am unable to Google it or name it.
I'm guessing you're looking to make a compression algorithm for your images. There isn't an algorithm that guarantees the minimum number of rectangles, as far as I'm aware.
The first thing that comes to mind is taking your pixel data as a 1D array and using run-length encoding to compress it. Images tend to have rather large groupings of similarly-colored pixels, so this should give you some data savings.
There are some things you can do on top of that to further increase the information density:
Like you suggested, start off with an image that is completely white and only store black pixels
If encoding time isn't an issue, run your encoding on both white and black pixels, then store whichever requires less data and use one bit to store whether the image should start with a black or a white background.
There are some algorithms that try to do this in two dimensions, but this seems to be quite a bit more complex. Here's one attempt I found on the topic:
https://pdfs.semanticscholar.org/d09a/62ea3472352bf7bbe873677cd81f348206cc.pdf
I found more interesting SO answers:
What algorithm can be used for packing rectangles of different sizes into the smallest rectangle possible in a fairly optimal way?
Minimum exact cover of grid with squares; extra cuts
Algorithm for finding the fewest rectangles to cover a set of rectangles without overlapping
https://mathoverflow.net/questions/244718/algo-for-covering-maximum-surface-of-a-polygon-with-rectangles
https://mathoverflow.net/questions/105837/get-largest-inscribed-rectangle-of-a-concave-polygon
https://mathoverflow.net/questions/80665/how-to-cover-a-set-in-a-grid-with-as-few-rectangles-as-possible
Converting monochrome image to minimum number of 2d shapes
I also read on Covering rectilinear polygons with axis-parallel rectangles.
I even found a code here: https://github.com/codecombat/codecombat/blob/6009df26de7c7938c0af2122ffba72c07123d172/app/lib/world/world_utils.coffee#L94-L148
I tested multiple approaches but in the end none were as fast as I needed or generated a reasonable amount of rectangles. So for now I went with a different approach.

How can I detect if there is a piece on chess square or not?

I have to detect a chess board and I do that as shown in this picture:
I divided this image in 64 sub-images which represent the black and white chess squares, like:
How can I check whether these sub-images (each square) contains a chess piece?
First you need to refine your squares detection, because you have some white region in the black and vice-versa. To do this quickly you can just crop a smaller ROI in the center of the square, assuming most of the piece will be in the center.
For the actual detection there are all kinds of simple options, which I guess will work perfectly fine in your case. Don't need to go to sophisticated feature detection and machine learning.
Options:
If you know the color of the square, use some threshold to find the piece.
You can look on the standard deviation of the gray level in the square. Without a piece it would be quite low, so you could use some threshold here.
You can do background subtraction with an empty square.
Either way, there will be some noise, so you will have to play with it a bit to find the best threshold/parameters.
Most of the time it is also better to do some pre-processing blur to get smoother results.
There are a lot of things that you need to consider:
Is necessary to have that perspective of the chess?. A top perspective can help you to make your process easier, by doing this you are avoiding an invasion of a piece in other square.
then you can check if there is a piece of chess in a square by checking the histogram of it. If the square doesn't have a piece you can appreciate a single peak in the curve, if there is a piece in that square you will appreciate more than one peak. You can use a threshold in the histogram to find if there is a single peak or not (by finding the max points in the histogram)

Using Opencv how to detect a box in image while eliminating objects printed inside box?

I am trying to develop box sorting application in qt and using opencv. I want to measure width and length of box.
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:
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.
Hough line transform gives me too many lines, i dont know how to get only four lines am interested in out of that.
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.
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.
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.
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
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

C++/OpenCV find objects on an image

I have to find a couple of objects on an image. For example find all black pawns on a chessboard:
How can I achieve that,using OpenCV ?
I think about cv::matchTemplate, however I'm not sure how would it proceed with different pawn backgrounds. I'm also not sure if I can easily get all matchings in that way.
Start with corner detection (well known shi tomasi method, or smt like line detection and intersection, since it should work better for your case) and collection of 64 subsamples of image -the squares. If the board is ideal - pure birds eye view -and you know the size (8x8 here), then just crop it into WxH pieces. You should save these samples with their coordinates (b6, h1 etc).
For every square, a low pass filter smt like gaussian, then otsu threshold and contour detection should give you at most one big contour. If there is none, that square is empty.
You can try to get the contours from the initial state of the board, and name them. This is your training data. Since pieces are not gonna differ much; 1 sample is enough :) Save a "white pawn"s (any square from 2nd row initially) area, hu moments and color (mean rgb value is OK). Then save a "black pawn". Then "white queen" and "black queen" (d4 d8). Do that area, moment, color table for all pieces.
Later, for any state of the board, you can try to match hu moments, color and area of your contour -output of those squares, using your identification table. Of course some statistical method like knn could help you there. You can also utilize matchShapes method.
At last you identify your contour smt like black knight, red checker piece, etc.

Are there algorithms for computing the bounding rects of sprites drawn on a monochrome background?

Imagine a plain rectangular bitmap of, say, 1024x768 pixels filled with white. There are a few (non-overlapping) sprites drawn onto the bitmap: circles, squares and triangles.
Is there an algorithm (possibly even a C++ implementation) which, given the bitmap and the color which is the background color (white, in the above example), yields a list containing the smallest bounding rectangles for each of the sprites?
Here's some sample: On the left side you can see a sample bitmap which my code is given (together with the information that the 'background' is white). On the right side you can see the same image together with the bounding rectangles of the four shapes (in red); the algorithm I'm looking for computes the geometry of these rectangles.
Some painting programs have a similiar feature for selecting shapes: they can even compute seemingly arbitrary bounding polygons. Instead of dragging a selection rectangle manually, you can click the 'background' (what's background and what's not is determined by some threshold) and then the tool automatically computes the shape of the object drawn onto the background. I need something like this, except that I'm perfectly fine if I just have the rectangular bounding areas for objects.
I became aware of OpenCV; it appears to be relevant (it seems to be a library which includes every graphics algorithm I can think of - and then some) but in the fast amount of information I couldn't find the way to the algorithm I'm thinking of. I would be surprised if OpenCV couldn't do this, but I fear you've got to have a PhD to use it. :-)
Here is the great article on the subject:
http://softsurfer.com/Archive/algorithm_0107/algorithm_0107.htm
I think that PhD is not required here :)
These are my first thoughts, none complicated, except for the edge detection
For each square,
if it's not-white
mark as "found"
if you havn't found one next to it already
add it to points list
for each point in the points list
use basic edge detection to find outline
keep track of bounds while doing so
add bounds to shapes list
remove duplicates from shapes list. (this can happen for concave shapes)
I just realized this will consider white "holes" (like in your leftmost circle in your sample) to be it's own shape. If the first "loop" is a flood fill, it doesn't have this problem, but will be much slower/take much more memory.
The basic edge detection I was thinking of was simple:
given eight cardinal directions left, downleft, etc...
given two relative directions cw(direction-1) and ccw(direction+1)
starting with a point "begin"
set bounds to point
find direction d, where the begin+d is not white, and begin+cw(d) is white.
set current to begin+d
do
if current is outside of bounds, increase bounds
set d = cw(d)
while(cur+d is white or cur+ccw(d) is not white)
d = ccw(d)
cur = cur + d;
while(cur != begin
http://ideone.com/
There's a quite a few edge cases not considered here: what if begin is a single point, what if it runs to the edge of the picture, what if start point is only 1 px wide, but has blobs to two sides, probably others... But the basic algorithm isn't that complicated.