【问题标题】:Measuring true angle of a bended wire with OpenCV使用 OpenCV 测量弯曲线的真实角度
【发布时间】:2020-01-14 11:47:59
【问题描述】:

我有一个弯曲电线的机器人设备,我尝试通过查看所需的真实角度测量值来衡量弯曲是否成功。

我的想法是检测电线并为电线的每一段画一条线,之后它就变成了一个小三角问题。但我找不到绘制和获取这些线条坐标的方法。

我对图像处理很陌生,所以请原谅我的粗俗术语。

【问题讨论】:

  • 看看:stackoverflow.com/questions/51169162/… 说不定会给你一个思路
  • 您可能会考虑 Canny 边缘检测,然后是 Hough 线检测。从霍夫线端点,您可以找到每个的斜率/交点,然后找到两条相关线的交点

标签: python opencv image-processing object-detection


【解决方案1】:

这看起来是一个有趣的问题。我们可以利用弯曲线和未弯曲线的垂直边缘强度不同的事实。当我们使用垂直 Sobel 过滤器过滤时,未弯曲的线将返回更高的值。

y方向sobel滤波器的结果

通过提取不同强度的区域(斑点)来提取弯曲和未弯曲的线。

更强的边缘将对应未弯曲的线。

较弱的边缘将对应弯曲的线。

通过opencv blob分析函数minRectArea,我们可以得到blob的角度、大小和中心位置。

角度值 w.r.t.水平线

未弯曲的电线:3.94 度

弯线:21.37 度

以下是用于获取上述结果的代码:

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

# extract blob with largest area
def get_best_blob(blobs):
    best_blob = None
    best_size = 0
    for i,blob in enumerate(blobs):
        rot_rect = cv2.minAreaRect(blob)
        (cx,cy),(sx,sy),angle = rot_rect
        if sx * sy >best_size :
            best_blob = rot_rect
            best_size = sx * sy
    
    return best_blob

def draw_blob_rect(frame,blob,color):
    box = cv2.boxPoints(blob)
    box = np.int0(box)    
    frame = cv2.drawContours(frame,[box],0,color,1)

    return frame

def process():
    image = cv2.imread("wire.png")

    # Change to grayscale
    gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    
    # Reduce size for speed
    gray = cv2.resize(gray,(0,0),fx=0.5,fy=0.5)

    # Extract wire region
    _ , thresh = cv2.threshold(gray,100,255,cv2.THRESH_BINARY_INV)

    # morphology kernel
    kernel = np.array((
            [1, 1, 1],
            [1, 1, 1],
            [1, 1, 1]
            ), dtype="int")
    
    # Get y-edges
    dy = cv2.Sobel(thresh,cv2.CV_32F,0,1,ksize=21)

    # remove negative values
    dy = dy * dy
    
    # Normalize it to 255
    cv2.normalize(dy,dy,norm_type=cv2.NORM_MINMAX,alpha=255)
    dy = dy.astype('uint8')

    # Extract relevant information
    # Stronger edge is the original part
    # Weaker edge is the bended part
    _ , strong = cv2.threshold(dy,0.95 * 255,255,cv2.THRESH_BINARY)
    _ , mid = cv2.threshold(dy,0.5 * 255,255,cv2.THRESH_BINARY)


    # Morphological closing to remove holes 
    strong_temp = cv2.dilate(strong,kernel, iterations=5)
    strong = cv2.erode(strong_temp,kernel, iterations=5)
    
    # remove the strong part from the mid
    mid = cv2.subtract(mid,strong_temp)

    # Morphological closing to remove holes 
    mid_temp = cv2.dilate(mid,kernel, iterations=5)
    mid = cv2.erode(mid_temp,kernel, iterations=5)

    # find the blobs for each bin image
    _,strong_blobs,_ = cv2.findContours(strong,cv2.RETR_EXTERNAL ,cv2.CHAIN_APPROX_SIMPLE)
    _,mid_blobs,_ = cv2.findContours(mid,cv2.RETR_EXTERNAL ,cv2.CHAIN_APPROX_SIMPLE)

    # get the blob with the largest area
    best_strong = get_best_blob(strong_blobs)
    best_mid = get_best_blob(mid_blobs)

    # print the angle
    print( "strong_angle",90 + best_strong[2])
    print( "mid_angle",90 + best_mid[2])

    
    # Draw the segmented Box region
    display_frame = cv2.cvtColor(gray,cv2.COLOR_GRAY2BGR)
    display_frame = draw_blob_rect(display_frame,best_strong,(0,0,255))
    display_frame = draw_blob_rect(display_frame,best_mid,(0,255,255))
    
    # draw result    
    cv2.imshow("display_frame",display_frame)
    cv2.imshow("mid",mid)
    cv2.imshow("strong",strong)
    cv2.imshow("image",image)
    cv2.imshow("dy",dy)
    cv2.waitKey(0)



if __name__=='__main__':
    process()

【讨论】:

  • 非常感谢,非常有帮助。在深入了解您的代码后,您意识到您可以稍微更改阈值以获取电线的不同区域。我尝试编辑代码以获取电线弯曲三次时的区域并设法获得所有三个区域,但是当弯曲次数增加时,它似乎变得相当复杂。当区域数量是任意的时,还有其他方法可以获取这些区域吗?
【解决方案2】:

这是一个非常宽泛的问题,所以我的回答也会有点宽泛。一种解决方法是:

  1. 获取二值图像的阈值,其中导线变为白色,背景变为黑色
  2. 执行连接组件标记
  3. 仅在黑色新图像上绘制第二大组件(忽略左侧的圆盘形状)
  4. 垂直求和此图像以找到从导线底部到导线的过渡(在列总和值中跳转)
  5. 确定从连线尖端(最左边的非零和列)到连线底部之前每一列的最顶部白色像素的 y 坐标
  6. 计算这些最顶部像素中的每一个到最左侧顶部像素和最右侧顶部像素之间的连线(就在基础之前)的距离
  7. 将拐点定位为该距离最大的列中的顶部像素
  8. 计算最左边的顶部像素和拐点之间的线的角度
  9. 比较水平,或者如果这部分也可以倾斜,则比较拐点和底部之前最右边顶部像素之间的线的角度

【讨论】:

    猜你喜欢
    • 2016-06-02
    • 2018-07-07
    • 2013-09-16
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多