Simple way with a BufferedImage
How to:
subImage = image.getSubimage(0, 550, image.getWidth(), 160);
where 550 - y coordinate, located higher than card content. 160 - cards content height.
Logic: We iterate for x - coordinate on cards content, and trying to find entry WHITE(gray) color points. If we find such an entry, we are sure that there is a card in front of us.
Now we move the x coordinate to the width of this entry and add the map width to it. Then we repeat this procedure. Example:
int count = 0;
int whiteColors = 0;
for (int y = 0; y < raster.getHeight(); y++) {
for (int x = 0; x < raster.getWidth(); x++) {
int RGBA = subImage.getRGB(x, y);
int red = (RGBA >> 16) & 255;
int green = (RGBA >> 8) & 255;
int blue = RGBA & 255;
if (red == WHITE_COLOR && green == WHITE_COLOR && blue == WHITE_COLOR
whiteColors++;
if (whiteColors == WHITE_COLOR_ENTRY) { // (entry = 30)
x = x + CARD_WIDTH - WHITE_COLOR_ENTRY; (card width = 64)
count++;
}
}
}
Okey, now we got cards count, those range and coordinates.
We know that there are only 4 suits - and 2 of them (Hearts and Diamonds) are red.
Solution for check a red suits is simple:
private void checkSuit() {
for (Map.Entry<Integer, Point> entry : DeckAnalyzer.cards.entrySet()) {
Point point = entry.getValue();
BufferedImage clipped = subImage.getSubimage(point.x, point.y, CARD_WIDTH, CARD_HEIGHT);
int reds = 0;
label:
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int RGBA = clipped.getRGB(x, y);
if (red > 60 && red > green * 2 && red > blue * 2)
reds++;
if (reds > 20)
break label;
}
}
}
if (reds > 0)
System.out.println(entry.getKey() + " is red!");
}
where Point(x, y) - a card coordinates on subImage.
The best explanation is visualization:
We know that diamonds is higher than hearts.
We start off from the bottom right point and simply measure the height of the shape's entry.
Again we starting from the bottom right point and looking for entries on the diagonal.
But now, unlike the previous algorithm, we only count the grow increment.
Before we start parsing cards, we transform the points of the horizontal entries into a byte array, from the start of the first point to the last.
Okay, now we got all suites, let's start looking for a deck.
Before I start explaining the map search approach, I have to show this shit:
The card cut algorithm looks awkward.
It can be seen that for the Queen and Ten, the value of the card goes beyond the bounds.
For the solution, we take any initial byte of the entry. If it is less, then it is Ten, if it is more then a Queen.
Above in the picture, we noticed that the King has a solid side. Therefore, we check for frequent repetition in the array.
int i;
for(i = 0; i < buffer.length; i++) {
if (buffer[i] != buffer[i + 1])
break;
}
if (i == buffer.length)
return Deck.King;
Both of these cards have the same point entries up to the middle.
To see their difference, it is enough to determine the growth increment at the bottom of the figure,
and compare the final grow index with the initial one.
We see continuous growth in these cards if we start from the end of the array of entry points.
For an Ace, this is one hundred percent growth to the beginning of the figure.
Seven has a little less, and Two has the smallest.
As a result, we just compare:
if (index < buffer.length / 2) {
if (index < 2) {
return Deck.ACE;
} else if (index < 5) {
return Deck.SEVEN;
} else {
return Deck.TWO;
}
}
Similar to the previous algorithm - we calculate the grow entries, but now we do it from the beginning of the figure.
Again we compare the last index with the first index:
if (index > buffer.length / 2)
return buffer[1] - buffer[index] > 7 ? Deck.FOUR : Deck.SEX;