Home > Net >  Multiple template matching with Scikit-image
Multiple template matching with Scikit-image

Time:03-30

I want to find the middle of a coin and find the radii. The radii can tell me if the coin is 5 cents of 50 cents. After finding the image, I must be able to detect the middle of the circles so I can give them a color

I already made a beginning with writing a code for Hough-transform

Hopefully someone can help me solve this exercise.

Code for hough transform:

image = img_as_ubyte(image)
edges = feature.canny(image, sigma=1.5, low_threshold=10, high_threshold=25)

# Detect two radii
hough_radii = np.arange(17, 35, 2)
hough_res = hough_circle(edges, hough_radii)

# Select the 11 coins
accums, cx, cy, radii = hough_circle_peaks(hough_res, hough_radii,total_num_peaks=11)

# Draw them
fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(10, 4))
image = color.gray2rgb(image)
count = 0
for center_y, center_x, radius in zip(cy, cx, radii):
    circy, circx = circle_perimeter(center_y, center_x, radius,
                                    shape=image.shape)
    image[circy, circx] = (220, 20, 20)
    count  = 1


ax.imshow(image)
plt.figure(figsize=(25,25))
print("In this image we can detect", count, "coins")
plt.show()

CodePudding user response:

You have 2 choices to find matching circles.

Sample Input and It's Edges

first one: sliding window

smaller windows is a template that you seek for it in input image, here two images with different radii 19 and 21 respectively. First at all, find edge of template and input image, after that, multiplying cropped part of image with template. each region that is near to template should have higher value.

def correlation_coefficient(patch1, patch2):
    product = np.mean((patch1 - patch1.mean()) * (patch2 - patch2.mean()))
    stds = patch1.std() * patch2.std()
    if stds == 0:
        return 0
    else:
        product /= stds
        return product


im1 =  cv2.imread("Original.jpg")
im1 = cv2.cvtColor(np.float32(im1), cv2.COLOR_BGR2GRAY)


im2 = cv2.imread("bigger.png")
im2 = cv2.cvtColor(np.float32(im2), cv2.COLOR_BGR2GRAY)


sh_row, sh_col = im1.shape
correlation = np.zeros_like(im1)

for i in range(sh_row - im2.shape[1]):
    for j in range(sh_col - im2.shape[0]):
        temp1 = im1[i : i   im2.shape[1], j : j   im2.shape[0]]
        if(temp1.shape != im2.shape):
          correlation[i, j] = 0
          continue
        correlation[i, j] = correlation_coefficient(temp1, im2)


fig = plt.figure(figsize=(10, 7))
plt.imshow(correlation, cmap=plt.cm.gray)
plt.show()

Here template is smaller or bigger one. output for bigger one is

Template Matching for Bigger Template

Template Matching for Smaller Template

As you can see some points highlighted as center of circles. Or by using second matching calculations:

im1 =  cv2.imread("Original.jpg")
im1 = cv2.cvtColor(np.float32(im1), cv2.COLOR_BGR2GRAY)

im1 = canny(im1, sigma=3, low_threshold=5, high_threshold=40)
im1 = im1.astype(np.uint8)

im2 = cv2.imread("bigger.png")
im2 = cv2.cvtColor(np.float32(im2), cv2.COLOR_BGR2GRAY)

im2 = canny(im2, sigma=3, low_threshold=5, high_threshold=40)
im2 = im2.astype(np.uint8)
sh_row, sh_col = im1.shape

d = 1

correlation = np.zeros_like(im1)

for i in range(sh_row - im2.shape[1]):
    for j in range(sh_col - im2.shape[0]):
        temp1 = im1[i : i   im2.shape[1], j : j   im2.shape[0]]
        if(temp1.shape != im2.shape):
          correlation[i, j] = 0
          continue
        correlation[i, j] = np.sum(np.multiply(temp1, im2))

io.imshow(correlation, cmap='gray')
io.show()

Also, we have same results:

Template Matching for Bigger Template in second Calculation Template Matching for Smaller Template in second Calculation

First method could not help us to find specified circles. Because you need to set a threshold for both templates and resolve more and more challenges. Let's investigate another method.

first one: Hough Transform

At first, run canny edge detector, then find all circles with radii range from 1 to 100. Then near circles(circles that centers are near to each others) are deleted:

import numpy as np
import matplotlib.pyplot as plt
import cv2
from skimage import data, color
from skimage.transform import hough_circle, hough_circle_peaks
from skimage.feature import canny
from skimage.draw import circle_perimeter
from skimage.util import img_as_ubyte
from skimage import io, feature
from scipy import ndimage
import imutils
from scipy import signal
from skimage import io, feature



image = cv2.imread("Original.jpg")
fig = plt.figure(figsize=(10, 7))

fig.add_subplot(1, 2, 1)
plt.imshow(image)
plt.axis('off')
plt.title("Original Image")

image = cv2.cvtColor(np.float32(image), cv2.COLOR_BGR2GRAY)
edges = canny(image, sigma=3, low_threshold=5, high_threshold=40)

fig.add_subplot(1, 2, 2)
plt.imshow(edges, cmap=plt.cm.gray)
plt.axis('off')
plt.title("After Run Canny Edge Detector")

# which raddii?
hough_radii = np.arange(1, 100)
hough_res = hough_circle(edges, hough_radii)

accums, cx, cy, radii = hough_circle_peaks(hough_res, hough_radii, total_num_peaks=100)
output = np.column_stack((cx, cy, radii))
output = output[(output[:,2] > 10)]

output = output[np.argsort(output[:, 1])]
output = output[np.argsort(output[:, 0])]

print(f"Circles Before Edit")
print(f"cx={output[:,0]}")
print(f"cy={output[:,1]}")
print(f"radii={output[:,2]}")

index = 0
flag = False
while (index < output.shape[0] - 1):

  if(abs (output[index][0] - output[index 1][0]) < 5 ):
    if(abs (output[index][1] - output[index 1][1]) < 5 ):
      # print(f"del index {index 1}")
      output = np.delete(output, (index 1), axis=0)
      flag = True
    else:
      flag = False
  else:
    flag = False
  if(flag is not True):
    index  = 1
print(f"Circles After Edit")
print(f"cx={output[:,0]}")
print(f"cy={output[:,1]}")
print(f"radii={output[:,2]}")


plt.show()


red = output[(output[:,2] <= 20)]
print(f"Red Circles")
print(f"cx={red[:,0]}")
print(f"cy={red[:,1]}")
print(f"radii={red[:,2]}")

green = output[(output[:,2] >= 20)]
print(f"Green Circles")
print(f"cx={green[:,0]}")
print(f"cy={green[:,1]}")
print(f"radii={green[:,2]}")

Check results:

Circles Before Edit
cx=[ 96  96  97  98 105 106 146 165 188 189 196 196 202 203 204 216 264 265]
cy=[137 138 136 138 232 232 356 229 102 102 166 166 222 221 286 322 116 116]
radii=[22 23 23 21 22 21 19 21 21 22 19 18 19 18 22 19 18 19]
Circles After Edit
cx=[ 96 105 146 165 188 196 202 204 216 264]
cy=[137 232 356 229 102 166 222 286 322 116]
radii=[22 22 19 21 21 19 19 22 19 18]

After do all necessary calculations:

Red Circles
cx=[146 196 202 216 264]
cy=[356 166 222 322 116]
radii=[19 19 19 19 18]
Green Circles
cx=[ 96 105 165 188 204]
cy=[137 232 229 102 286]
radii=[22 22 21 21 22]

As mentioned in results, 5 circles are proposed to red and 5 circles proposed to green.

Update#1

Be cautious before doing preprocessing in such problems. These processing likes erosion, dilation and median filters change radius of circles.

Drawing Circles:

Input radius are 19 and 21, so radius larger than 20 are belong to green color and radius smaller than 20 are belong to red color. For simplicity I set yellow color for radius = 20. In the last step you should delete abundance circles. Bellow I bring all of them together:

def remove_redundance(output):
  
  print(f"output.shape={output.shape}")
  index = 0
  del_first = False
  index_first = 0
  while (index_first < output.shape[0]):
    index_second = index_first   1
    del_second = False
    while (index_second < output.shape[0]):

      if( (abs(output[index_first][0] - output[index_second][0]) < 10) and 
         (abs(output[index_first][1] - output[index_second][1]) < 10) ):
        
        if(output[index_first][3] > output[index_second][3]):
          output = np.delete(output, (index_second), axis=0)
          del_second = True
        else:
          output = np.delete(output, (index_first), axis=0)
          del_first = True
          break

      else:
        del_second = False
        del_first = False

      if (del_second == False):
        index_second  = 1
    
    
    if (del_first == False):
      index_first  = 1
    else:
      del_first = False

  print(f"output.shape={output.shape}")
  return output
  

def draw_circles(circle, coordinate, green = 0):
  for cx, cy, radii in zip(coordinate[:,0], coordinate[:,1], coordinate[:,2]):
    # Center coordinates
    center_coordinates = (int(cx), int(cy))
    
    # Radius of circle
    radius = int(radii)
    
    if(green == 1):
      color = (0, 255, 0)
    elif(green == 0):
      color = (0, 0, 255)
    elif(green == -1):
      color = (0, 255, 255)
      
    thickness = 1#-1
      
    circle = cv2.circle(circle, center_coordinates, radius, color, thickness)

  return circle



image = cv2.imread("Original.jpg")
# image = cv2.medianBlur(image, 3)
fig = plt.figure(figsize=(10, 7))

fig.add_subplot(1, 2, 1)
plt.imshow(image)
plt.axis('off')
plt.title("Original Image")

image = cv2.cvtColor(np.float32(image), cv2.COLOR_BGR2GRAY)
edges = canny(image, sigma=3, low_threshold=5, high_threshold=40)

fig.add_subplot(1, 2, 2)
plt.imshow(edges, cmap=plt.cm.gray)
plt.axis('off')
plt.title("After Run Canny Edge Detector")

# which raddii?
hough_radii = np.arange(1, 500)
hough_res = hough_circle(edges, hough_radii)

accums, cx, cy, radii = hough_circle_peaks(hough_res, hough_radii, total_num_peaks=500)
output = np.column_stack((cx, cy, radii, accums))#
output = output[(output[:,2] > 10)]

output = output[np.argsort(output[:, 1])]
output = output[np.argsort(output[:, 0])]

print(f"Circles Before Edit")
print(f"cx={output[:,0]}")
print(f"cy={output[:,1]}")
print(f"radii={output[:,2]}")


output = remove_redundance(output)


print(f"Circles After Edit")
print(f"cx={output[:,0]}")
print(f"cy={output[:,1]}")
print(f"radii={output[:,2]}")


plt.show()


red = output[(output[:,2] < 20)]
if(red.shape[0]>0):
  print(f"Red Circles")
  print(f"cx={red[:,0]}")
  print(f"cy={red[:,1]}")
  print(f"radii={red[:,2]}")

green = output[(output[:,2] > 20)]
if(green.shape[0]>0):
  print(f"Green Circles")
  print(f"cx={green[:,0]}")
  print(f"cy={green[:,1]}")
  print(f"radii={green[:,2]}")


yellow = output[(output[:,2] == 20)]
if(yellow.shape[0]>0):
  print(f"yellow Circles")
  print(f"cx={yellow[:,0]}")
  print(f"cy={yellow[:,1]}")
  print(f"radii={yellow[:,2]}")


circle = cv2.imread("Original.jpg")

if(red.shape[0]>0):
  circle  = draw_circles(circle, red, green = 0)
if(green.shape[0]>0):
  circle  = draw_circles(circle, green, green = 1)
if(yellow.shape[0]>0):
  circle  = draw_circles(circle, yellow, green = -1)

circle = cv2.cvtColor(circle, cv2.COLOR_BGR2RGB)

fig = plt.figure(figsize=(10, 7))
plt.imshow(circle)
plt.axis('off')
plt.title("Circles") 

Results:

Results

  • Related