与 Scikit-image 匹配的多模板
Multiple template matching with Scikit-image
我想找到一枚硬币的中间并求出半径。半径可以告诉我硬币是 5 美分还是 50 美分。找到图像后,我必须能够检测到圆圈的中间,这样我才能给它们上色
我已经开始为霍夫变换编写代码
希望有人能帮我解决这个问题。
霍夫变换代码:
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()
您有 2 个选择可以找到匹配的圈子。
第一个:滑动window
smaller windows 是您在输入图像中寻找的模板,这里有两个不同半径的图像分别为 19 和 21。首先,找到模板和输入图像的边缘,然后将图像的裁剪部分与模板相乘。每个靠近模板的区域都应该有更高的值。
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()
这里的模板是小一点的还是大一点的。更大的输出是
如您所见,一些点突出显示为圆心。或者通过使用第二个匹配计算:
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()
此外,我们有相同的结果:
第一种方法无法帮助我们找到指定的圈子。因为你需要为两个模板都设置一个门槛,解决越来越多的挑战。让我们研究另一种方法。
第一个:霍夫变换
首先,运行canny边缘检测器,然后找出所有半径范围为1到100的圆。然后删除近圆(中心彼此靠近的圆):
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]}")
检查结果:
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]
完成所有必要的计算后:
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]
如结果中所述,5 个圆圈 被提议为 红色 和 5 个圆圈 被提议到 绿色.
更新#1
对此类问题进行预处理前要谨慎。这些处理如腐蚀、膨胀和中值滤波器改变圆的半径。
画圆:
输入半径为19和21,半径大于20为绿色,半径小于20为红色。为简单起见,我将半径设置为黄色 = 20。在最后一步中,您应该删除丰度圆。下面我将所有这些放在一起:
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")
结果:
我想找到一枚硬币的中间并求出半径。半径可以告诉我硬币是 5 美分还是 50 美分。找到图像后,我必须能够检测到圆圈的中间,这样我才能给它们上色
我已经开始为霍夫变换编写代码
希望有人能帮我解决这个问题。
霍夫变换代码:
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()
您有 2 个选择可以找到匹配的圈子。
第一个:滑动window
smaller windows 是您在输入图像中寻找的模板,这里有两个不同半径的图像分别为 19 和 21。首先,找到模板和输入图像的边缘,然后将图像的裁剪部分与模板相乘。每个靠近模板的区域都应该有更高的值。
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()
这里的模板是小一点的还是大一点的。更大的输出是
如您所见,一些点突出显示为圆心。或者通过使用第二个匹配计算:
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()
此外,我们有相同的结果:
第一种方法无法帮助我们找到指定的圈子。因为你需要为两个模板都设置一个门槛,解决越来越多的挑战。让我们研究另一种方法。
第一个:霍夫变换
首先,运行canny边缘检测器,然后找出所有半径范围为1到100的圆。然后删除近圆(中心彼此靠近的圆):
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]}")
检查结果:
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]
完成所有必要的计算后:
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]
如结果中所述,5 个圆圈 被提议为 红色 和 5 个圆圈 被提议到 绿色.
更新#1
对此类问题进行预处理前要谨慎。这些处理如腐蚀、膨胀和中值滤波器改变圆的半径。
画圆:
输入半径为19和21,半径大于20为绿色,半径小于20为红色。为简单起见,我将半径设置为黄色 = 20。在最后一步中,您应该删除丰度圆。下面我将所有这些放在一起:
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")
结果: