【问题标题】:Finding Teeth of Gear by python opencv通过 python opencv 寻找齿轮的牙齿
【发布时间】:2019-08-12 10:49:28
【问题描述】:

我正在学习 OpenCv。我有一个斜齿轮图像来寻找齿。

到目前为止,我一直试图找到轮廓,然后数牙齿。我能够找到轮廓也轮廓的坐标。但我坚持数牙齿。 由于我是 OpenCV 的新手,可能是我试图找到牙齿的方式不正确。

我的代码:

import cv2
import numpy as np
import scipy as sp
import imutils
from skimage.morphology import reconstruction

import csv

raw_image = cv2.imread('./Gear Image/new1.jpg')
#cv2.imshow('Original Image', raw_image)
#cv2.waitKey(0)

bilateral_filtered_image = cv2.bilateralFilter(raw_image, 5, 175, 175)
#cv2.imshow('Bilateral', bilateral_filtered_image)
#cv2.waitKey(0)

edge_detected_image = cv2.Canny(bilateral_filtered_image, 75, 200)
#cv2.imshow('Edge', edge_detected_image)
#cv2.waitKey(0)



contours, hierarchy = cv2.findContours(edge_detected_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)





contour_list = []
for contour in contours:
    approx = cv2.approxPolyDP(contour,0.01*cv2.arcLength(contour,True),True)
    area = cv2.contourArea(contour)
    if ((len(approx) > 5) & (len(approx) < 25) & (area > 50) ):
        contour_list.append(contour)



cv2.drawContours(raw_image, contour_list,  -1, (255,0,0), 2)


c = max(contours, key = cv2.contourArea)
M = cv2.moments(c)

cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])

cv2.circle(raw_image, (cX, cY), 5, (142, 152, 100), -1)
cv2.putText(raw_image, "centroid", (cX - 25, cY - 25),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (142, 152, 100), 2)

contour_length = "Number of contours detected: {}".format(len(contours))
cv2.putText(raw_image,contour_length , (20,40),  cv2.FONT_HERSHEY_SIMPLEX, 0.5, (142, 152, 100), 2)

for c in range(len(contours)):
        n_contour = contours[c]
        for d in range(len(n_contour)):
            XY_Coordinates = n_contour[d]


print(len(coordinates))
print(XY_Coordinates)
print(type(XY_Coordinates))
print(XY_Coordinates[0,[0]])
print(XY_Coordinates[0,[1]])



cv2.imshow('Objects Detected',raw_image)
cv2.waitKey(0)

输入图片:

我得到的输出图像:

在这个阶段之后,我该如何计算牙齿? 我可以使用坐标来计算间隔和计算牙齿。

或者有没有其他方法可以计算这个阶段之后的牙齿?

【问题讨论】:

    标签: python opencv opencv-contour


    【解决方案1】:

    我的解决方案的第一部分与@HansHirse 发布的答案相似,但我使用了不同的方法来计算牙齿。我的完整代码可以在这里找到:link to full code for python3 opencv4。在继续之前检查是否正确检测到齿轮的外轮廓。如果未正确检测到齿轮,则其余答案将不起作用。

    在数齿数之前,我“打开”了齿轮。我通过扫描齿轮并计算从齿轮中心到齿外的距离来做到这一点。

    这是我用来绕齿轮扫一圈,求齿轮中心到齿轮外侧距离的代码:

    # Start at angle 0, and increment the angle 1/200 rad
    angle = 0
    increment = 1/200
    # Create a list for the distances from the centroid to the edge of the gear tooth
    distances = []
    # Create an image for display purposes
    display_image = raw_image.copy()
    # Sweep around the circle (until one full revolution)
    while angle < 2*math.pi:
        # Compute a ray from the center of the circle with the current angle
        img_size = max(raw_image.shape)
        ray_end = int(math.sin(angle) * img_size + cX), int(math.cos(angle) * img_size + cY)
        center = cX, cY
        # Create mask
        mask = np.zeros((raw_image.shape[0], raw_image.shape[1]), np.uint8)
        # Draw a line on the mask
        cv2.line(mask, center, ray_end, 255, 2)
        # Mask out the gear slice (this is the portion of the gear the us below the line)
        gear_slice = cv2.bitwise_and(raw_image, raw_image, mask = mask)
        # Threshold the image
        _, thresh = cv2.threshold(cv2.cvtColor(gear_slice, cv2.COLOR_BGR2GRAY), 0 , 255, 0)
        # Find the contours in the edge_slice
        _, edge_slice_contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        # Get the center of the edge slice contours
        M = cv2.moments(max(edge_slice_contours, key = cv2.contourArea))
        edge_location = int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"])
        cv2.circle(display_image, edge_location, 0, (0,255,0), 4)
        # Find the distance from the center of the gear to the edge of the gear...at this specific angle
        edge_center_distance = distance(center, edge_location)
        # Find the xy coordinates for this point on the graph - draw blue circle
        graph_point = int(angle*0.5*raw_image.shape[1]/math.pi), int(edge_center_distance+ 1.5*gear_radius)
        cv2.circle(display_image, graph_point, 0, (0,255,0), 2)    
        # Add this distance to the list of distances
        distances.append(-edge_center_distance)
        # Create a temporary image and draw the ray on it
        temp = display_image.copy()
        cv2.line(temp, ray_end, (cX,cY), (0,0,255), 2)
        # Show the image and wait
        cv2.imshow('raw_image', temp)
        vid_writer.write(temp)
        k = cv2.waitKey(1)
        if k == 27: break
        # Increment the angle
        angle += increment
    # Clean up
    cv2.destroyAllWindows()
    

    其结果是齿距与齿轮中心的角度函数。

    import matplotlib.pyplot as plt
    plt.plot(distances)
    plt.show()
    

    现在计算齿数要容易得多,因为它们是函数中的峰(或者在本例中是谷 - 稍后会详细介绍)。为了数山峰,我拿了 Fourier transform的齿距函数。

    import scipy.fftpack
    # Calculate the Fourier transform
    yf = scipy.fftpack.fft(distances)
    fig, ax = plt.subplots()
    # Plot the relevant part of the Fourier transform (a gear will have between 2 and 200 teeth)
    ax.plot(yf[2:200])
    plt.show()
    

    傅里叶变换的峰值出现在 37 处,因此有 37 个谷底和 38 个轮齿。

    num_teeth = list(yf).index(max(yf[2:200])) - 1
    print('Number of teeth in this gear: ' + str(num_teeth))
    

    【讨论】:

    • 不错的解决方案和动画!如果你展示你的代码会更有用 - 你肯定有吗?
    • 嗨@StephenMeschke,这对我来说是一个很好的学习。感谢逐步指导。但是在“,轮廓,_ = cv2.findContours(edge_detected_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) ValueError: no enough values to unpack (expected 3, got 2)”中运行代码时出现错误,知道为什么吗?跨度>
    • 我通过在行中添加层次结构来解决它。但是如果我更改了我看到的图像并且错误是“M = cv2.moments(max(edge_slice_contours, key = cv2.contourArea)) ValueError: max() arg is an empty sequence”.. 对此有什么想法吗?跨度>
    • 嗨@Subhasish1315。我更改了Github Gist 中的代码。您收到错误消息,因为未正确检测到齿轮。我也对我的回答做了一些更新。
    【解决方案2】:

    也许以下解决方案适合您。

    • 我在双边滤波后添加了一些轻微的中值模糊,以改进以下边缘检测(更少的微小边缘)。
    • findContours 中,我从RETR_TREE 切换到RETR_EXTERNAL 以仅获取最外侧的轮廓。
    • 为此,我确定了轮廓的凸包,并确保每个牙齿只有一个凸包点。
    • 这些“稀疏”凸包点的结果数就是齿数。

    (我删除了你的一些不必要的代码以保持答案简短。)

    import cv2
    import numpy as np
    
    raw_image = cv2.imread('images/vChAL.jpg')
    
    bilateral_filtered_image = cv2.bilateralFilter(raw_image, 5, 175, 175)
    
    # Added median blurring to improve edge detection
    median_blurred_images = cv2.medianBlur(bilateral_filtered_image, 5)
    
    edge_detected_image = cv2.Canny(median_blurred_images, 75, 200)
    
    # Switched from RETR_TREE to RETR_EXTERNAL to only extract most outer contours
    contours, _ = cv2.findContours(edge_detected_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    contour_list = []
    for contour in contours:
        approx = cv2.approxPolyDP(contour,0.01*cv2.arcLength(contour,True),True)
        area = cv2.contourArea(contour)
        if ((len(approx) > 5) & (len(approx) < 25) & (area > 50) ):
            contour_list.append(contour)
    
    cv2.drawContours(raw_image, contour_list, -1, (255, 0, 0), 2)
    
    c = max(contours, key = cv2.contourArea)
    
    contour_length = "Number of contours detected: {}".format(len(contours))
    cv2.putText(raw_image,contour_length , (20, 40),  cv2.FONT_HERSHEY_SIMPLEX, 0.5, (142, 152, 100), 2)
    
    # Determine convex hull of largest contour
    hull = cv2.convexHull(c, clockwise = True, returnPoints = False)
    
    # Debug: Draw "raw" convex hull points (green)
    cv2.drawContours(raw_image, c[hull], -1, (0, 255, 0), 3)
    
    # Determine convex hull, such that nearby convex hull points are "grouped"
    sparsehull = []
    for idx in hull:
        if (len(sparsehull) == 0):
            sparsehull.append(idx)
        else:
            last = sparsehull[-1]
            diff = c[idx] - c[last]
            if (cv2.norm(diff) > 40):
                sparsehull.append(idx)
    sparsehull = np.asarray(sparsehull)
    
    # Debug: Draw "sparse2 convex hull points (red)
    cv2.drawContours(raw_image, c[sparsehull], -1, (0, 0, 255), 3)
    
    # Additional output on image
    teeth_length = "Number of teeth detected: {}".format(len(sparsehull))
    cv2.putText(raw_image, teeth_length , (20, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (142, 152, 100), 2)
    
    cv2.imshow('Objects Detected', raw_image)
    cv2.waitKey(0)
    

    免责声明:总的来说,我是 Python 新手,尤其是 OpenCV 的 Python API(C++ for the win)。非常欢迎评论、改进、突出 Python 的禁忌!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-12
      • 2018-08-27
      • 2014-04-11
      • 2013-07-10
      • 1970-01-01
      相关资源
      最近更新 更多