0

I want to automatically divide an image of multiple coins to the single coins, so that afterwards the single coins can be put into a model that classifies the coins (with Tensorflow/Keras).

The input images look something like this

And they should look like this (Sorry that I cannot integrate the images directly as I'm new to StackOverflow).

I want to divide the input images, put the single coins into a classification model, so that I know the single value of the single coins and thereby can identify the value of the first input image.

I already tried an object detection model, but it didn't detect coins (https://towardsdatascience.com/object-detection-with-10-lines-of-code-d6cb4d86f606). As I already know that all objects on the image are coins, I thought that there is maybe an easier way to divide the image?

Thank you in advance.

Community
  • 1
  • 1
chris
  • 155
  • 1
  • 10
  • The proper path is to use an object detection model to define the coin boundaries. As far as I know, there isn't a simpler way. However, there are a number of good object detection libraries that will do this for you (ex: [Tensorflow's object detection API](https://github.com/tensorflow/models/tree/master/research/object_detection). Can you share what you've already tried? – Myles Baker Sep 05 '18 at 19:31
  • You want to use the distance transform + watershed method. See for example https://stackoverflow.com/questions/25789278/coffee-beans-separation-algorithm or https://stackoverflow.com/questions/19385264/image-segmentation-of-connected-objects-with-watershed – Cris Luengo Sep 05 '18 at 22:23

2 Answers2

1

I would try color segmentation similar to this tutorial as a first step to separate the coins from the background. Here is my quick try in Python using OpenCV:

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("coins.jpg")

lower = np.array([0,40,5])
upper = np.array([255,255,255])
mask = cv2.inRange(hsv, lower, upper)

cv2.imshow(img)
plt.show()
plt.imshow(mask)

This brings us from the input image

enter image description here

to this mask:

enter image description here

From here using blob analysis and a size filter you should be able to find and separate the unconnected coins. Disconnecting the overlapping areas could be achieved using active contours, or since your goal is to create a training data set, by shifting the coins before taking the picture.

Herr von Wurst
  • 2,571
  • 5
  • 32
  • 53
0

enter image description here

import cv2
import imutils
import numpy as np
import matplotlib.pyplot as plt

def display(img,count,cmap="gray"):
    f_image = cv2.imread("coins.jpg")
    f, axs = plt.subplots(1,2,figsize=(12,5))
    axs[0].imshow(f_image,cmap="gray")
    axs[1].imshow(img,cmap="gray")
    axs[1].set_title("Total Money Count = {}".format(count))


image = cv2.imread("coins.jpg")
image_blur = cv2.medianBlur(image,25)
image_blur_gray = cv2.cvtColor(image_blur, cv2.COLOR_BGR2GRAY)
image_res ,image_thresh = cv2.threshold(image_blur_gray,240,255,cv2.THRESH_BINARY_INV)
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(image_thresh,cv2.MORPH_OPEN,kernel)
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
ret, last_image =  cv2.threshold(dist_transform, 0.3*dist_transform.max(),255,0)
last_image = np.uint8(last_image)

cnts = cv2.findContours(last_image.copy(), cv2.RETR_EXTERNAL,
    cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)


for (i, c) in enumerate(cnts):
    ((x, y), _) = cv2.minEnclosingCircle(c)
    cv2.putText(image, "#{}".format(i + 1), (int(x) - 45, int(y)+20),
        cv2.FONT_HERSHEY_SIMPLEX, 2, (255, 0, 0), 5)
    cv2.drawContours(image, [c], -1, (0, 255, 0), 2)

display(image,len(cnts))
Furkan Gulsen
  • 1,384
  • 2
  • 12
  • 24