如何用opencv读取实用仪表针?

时间:2017-10-01 14:23:37

标签: c++ opencv computer-vision

我不一定需要源代码,但要查找伪代码或如何处理此问题的想法。我有一个相机指向我的水表,并希望将使用情况记录到数据库中。过去几周我一直在玩OpenCV并且数字检测工作正常。 (最后一个数字会产生问题,因为它会无休止地旋转,而不是像前5个那样与数字对齐,所以整个数字在视野中的时间不到一半。)

无论如何,为了获得最佳分辨率,我想跟踪实际的大红针。现在我走了一圈,找到了最红的"像素,并用它来计算针的角度。只要灯光合适且相机不动,它就可以工作。

我猜测我可以使用Canny边缘检测技巧...最终我只是想找到最长线的角度?并且针是一种独特的颜色应该有助于消除许多误报,但我如何实际应用过滤器?

(请注意,仪表左下方有一个小红色旋转器,与针头颜色相同。我需要确保不会触发某些东西。)

谢谢! - 亚当Water Meter Example

1 个答案:

答案 0 :(得分:3)

国庆节快乐,中秋节快乐!O(∩_∩)O哈哈哈〜

新答案:

嗨,今天我对这个问题进行了一些研究,经过多次反复试验,我现在得到了一个很好的解决方案。结果如下。

enter image description here

基本步骤如下:

  1. 转换为灰度,阈值,项目到轴,这样我们就可以找到监视区域。
  2. 转换为Lab-color-space,因此可以在a通道中轻松区分红色针(暖色)。
  3. 规范化a通道,阈值并进行形态学操作,因此我们得到二进制掩码。在这些操作之后,它将用于找到潜在的红色针区域。
  4. 在掩码中查找轮廓,按某些属性进行过滤,然后就可以得到它。
  5. 1。找到手表区域

    # https://i.stack.imgur.com/5oOGL.jpg
    imgname = "stkdata/5oOGL.jpg"
    img = cv2.imread(imgname)
    ## Threshold in grayscale
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    retval, threshed = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY )
    
    ## Find wathc region by counting the projector
    h,w = img.shape[:2]
    x = np.sum(threshed, axis=0)
    y = np.sum(threshed, axis=1)
    yy = np.nonzero(y>(w/5*255))[0]
    xx = np.nonzero(x > (h/5*255))[0]
    region = img[yy[0]:yy[-1], xx[0]:xx[-1]]
    #cv2.imwrite("region.png", region)
    

    enter image description here

    2。转换为LAB

    ## Change to LAB space
    lab = cv2.cvtColor(region, cv2.COLOR_BGR2LAB)
    l,a,b = cv2.split(lab)
    imglab = np.hstack((l,a,b))
    cv2.imwrite("region_lab.png", imglab)
    

    在实验室色彩空间中,可以很容易地区分红色针。

    enter image description here

    3。标准化a通道,阈值,并进行形态学操作。

    ## normalized the a channel to all dynamic range
    na = cv2.normalize(a, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC1)
    cv2.imwrite("region_a_normalized.png", na)
    
    ## Threshold to binary
    retval, threshed = cv2.threshold(na, thresh = 180,  maxval=255, type=cv2.THRESH_BINARY)
    
    ## Do morphology
    kernel = cv2.getStructuringElement( cv2.MORPH_ELLIPSE , (3,3))
    opened = cv2.morphologyEx(threshed, cv2.MORPH_OPEN,kernel)
    res = np.hstack((threshed, opened))
    cv2.imwrite("region_a_binary.png", res)
    

    规范化频道:

    enter image description here

    阈值并进行形态学操作,我们得到一个二元掩码作为右侧。

    enter image description here

    4。查找轮廓,并按某些属性(例如区域等)过滤它们。

    ## Find contours
    contours = cv2.findContours(opened, mode=cv2.RETR_LIST, method=cv2.CHAIN_APPROX_SIMPLE)[-2]
    
    ## Draw Contours
    res = region.copy()
    cv2.drawContours(res, contours, -1, (255,0,0), 1)
    cv2.imwrite("region_contours.png", res)
    
    ## Filter Contours
    for idx, contour in enumerate(contours):
        bbox = cv2.boundingRect(contour)
        area = bbox[-1]*bbox[-2]
        if area < 100:
            continue
        rot_rect = cv2.minAreaRect(contour)
        (cx,cy), (w,h), rot_angle = rot_rect
        rbox = np.int0(cv2.boxPoints(rot_rect))
        cv2.drawContours(res, [rbox], 0, (0,255,0), 1)
        text="#{}: {:2.3f}".format(idx, rot_angle)
        org=(int(cx)-10,int(cy)-10)
        cv2.putText(res, text=text, org = org, fontFace = 1, fontScale=0.8, color=(0,0,255), thickness = 1, lineType=16)
    
    cv2.imwrite("region_result.png", res)
    

    成立的轮廓:

    enter image description here

    结果:

    enter image description here

    我们可以发现,#1轮廓属于红色针,它的角度是-85.601。

    (右方向为0°,逆时针为负,顺时针为正)

    此处提供了所有Python代码:

    #!/usr/bin/python3
    # 2017.10.01 22:59:02 CST
    # 2017.10.03 23:49:18 CST
    
    import numpy as np
    import cv2
    
    # https://i.stack.imgur.com/5oOGL.jpg
    imgname = "stkdata/5oOGL.jpg"
    img = cv2.imread(imgname)
    ## Threshold in grayscale
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    retval, threshed = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY )
    
    ## Find wathc region by counting the projector
    h,w = img.shape[:2]
    x = np.sum(threshed, axis=0)
    y = np.sum(threshed, axis=1)
    yy = np.nonzero(y>(w/5*255))[0]
    xx = np.nonzero(x > (h/5*255))[0]
    region = img[yy[0]:yy[-1], xx[0]:xx[-1]]
    cv2.imwrite("region.png", region)
    
    ## Change to LAB space
    lab = cv2.cvtColor(region, cv2.COLOR_BGR2LAB)
    l,a,b = cv2.split(lab)
    imglab = np.hstack((l,a,b))
    cv2.imwrite("region_lab.png", imglab)
    
    ## normalized the a channel to all dynamic range
    na = cv2.normalize(a, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC1)
    cv2.imwrite("region_a_normalized.png", na)
    
    ## Threshold to binary
    retval, threshed = cv2.threshold(na, thresh = 180,  maxval=255, type=cv2.THRESH_BINARY)
    
    ## Do morphology
    kernel = cv2.getStructuringElement( cv2.MORPH_ELLIPSE , (3,3))
    opened = cv2.morphologyEx(threshed, cv2.MORPH_OPEN,kernel)
    res = np.hstack((threshed, opened))
    cv2.imwrite("region_a_binary.png", res)
    
    ## Find contours
    contours = cv2.findContours(opened, mode=cv2.RETR_LIST, method=cv2.CHAIN_APPROX_SIMPLE)[-2]
    
    ## Draw Contours
    res = region.copy()
    cv2.drawContours(res, contours, -1, (255,0,0), 1)
    cv2.imwrite("region_contours.png", res)
    
    ## Filter Contours
    for idx, contour in enumerate(contours):
        bbox = cv2.boundingRect(contour)
        area = bbox[-1]*bbox[-2]
        if area < 100:
            continue
        rot_rect = cv2.minAreaRect(contour)
        (cx,cy), (w,h), rot_angle = rot_rect
        rbox = np.int0(cv2.boxPoints(rot_rect))
        cv2.drawContours(res, [rbox], 0, (0,255,0), 1)
        text="#{}: {:2.3f}".format(idx, rot_angle)
        org=(int(cx)-10,int(cy)-10)
        #cv2.putText(res, text=text, org = org, fontFace = cv2.FONT_HERSHEY_PLAIN, fontScale=0.7, color=(0,0,255), thickness = 1, lineType=cv2.LINE_AA)
        cv2.putText(res, text=text, org = org, fontFace = 1, fontScale=0.8, color=(0,0,255), thickness = 1, lineType=16)
    
    cv2.imwrite("region_result.png", res)
    cv2.imshow("result", res); cv2.waitKey();cv2.destroyAllWindows()
    

    原点答案:

    我认为首先你可以提取手表区域,然后在区域内搜索红色针,你可以改变色彩空间。这是我在python中的示例代码。

    imgname = "5oOGL.jpg"
    # https://i.stack.imgur.com/5oOGL.jpg
    img = cv2.imread(imgname)
    
    ## Threshold in grayscale
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    th, imgbin = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY )
    
    ## Find watch region by projecting and counting
    h,w = img.shape[:2]
    x = np.sum(imgbin, axis=0)
    y = np.sum(imgbin, axis=1)
    yy = np.nonzero(y>(w/5*255))[0]
    xx = np.nonzero(x > (h/5*255))[0]
    region = img[yy[0]:yy[-1], xx[0]:xx[-1]]
    cv2.imwrite("region.png", region)
    cv2.imshow("region", region); cv2.waitKey(0);# cv2.destroyAllWindows()
    
    ## Change to LAB space
    lab = cv2.cvtColor(region, cv2.COLOR_BGR2LAB)
    l,a,b = cv2.split(lab)
    imglab = np.hstack((l,a,b))
    cv2.imwrite("imglab.png", imglab)
    

    手表区域 Watch region

    实验室空间中的手表区域。 Watch region in LAB

    一些链接:

    1. Choosing the correct upper and lower HSV boundaries for color detection with`cv::inRange` (OpenCV)

    2. How to use `cv2.findContours` in different OpenCV versions?

    3. How to find the RED color regions using OpenCV?