簡體   English   中英

如何用Python檢測圖像中的矩形項

[英]How to detect rectangular items in image with Python

我發現了很多關於使用openCV等人在圖像中找到“東西”的問題。 在Python中,但到目前為止,我無法將它們拼湊在一起,以便為我的問題提供可靠的解決方案。

我正在嘗試使用計算機視覺來幫助計算微小的表面貼裝電子部件。 我的想法是讓我將零件轉移到一張純色紙上,拍下一張照片,讓軟件告訴我里面有多少物品。

“事物”從一張圖片到另一張圖片不同,但在任何一張圖片中總是相同的。 我似乎能夠手動調整特定部件的色調/飽和度等參數,但每次更換新部件時都需要調整。

我目前的半功能代碼發布如下:

import imutils
import numpy
import cv2
import sys

def part_area(contours, round=10):
    """Finds the mode of the contour area.  The idea is that most of the parts in an image will be separated and that
    finding the most common area in the list of areas should provide a reasonable value to approximate by.  The areas
    are rounded to the nearest multiple of 200 to reduce the list of options."""
    # Start with a list of all of the areas for the provided contours.
    areas = [cv2.contourArea(contour) for contour in contours]
    # Determine a threshold for the minimum amount of area as 1% of the overall range.
    threshold = (max(areas) - min(areas)) / 100
    # Trim the list of areas down to only those that exceed the threshold.
    thresholded = [area for area in areas if area > threshold]
    # Round the areas to the nearest value set by the round argument.
    rounded = [int((area + (round / 2)) / round) * round for area in thresholded]
    # Remove any areas that rounded down to zero.
    cleaned = [area for area in rounded if area != 0]
    # Count the areas with the same values.
    counts = {}
    for area in cleaned:
        if area not in counts:
            counts[area] = 0
        counts[area] += 1
    # Reduce the areas down to only those that are in groups of three or more with the same area.
    above = []
    for area, count in counts.iteritems():
        if count > 2:
            for _ in range(count):
                above.append(area)
    # Take the mean of the areas as the average part size.
    average = sum(above) / len(above)
    return average

def find_hue_mode(hsv):
    """Given an HSV image as an input, compute the mode of the list of hue values to find the most common hue in the
    image.  This is used to determine the center for the background color filter."""
    pixels = {}
    for row in hsv:
        for pixel in row:
            hue = pixel[0]
            if hue not in pixels:
                pixels[hue] = 0
            pixels[hue] += 1
    counts = sorted(pixels.keys(), key=lambda key: pixels[key], reverse=True)
    return counts[0]


if __name__ == "__main__":
    # load the image and resize it to a smaller factor so that the shapes can be approximated better
    image = cv2.imread(sys.argv[1])

    # define range of blue color in HSV
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    center = find_hue_mode(hsv)
    print 'Center Hue:', center

    lower = numpy.array([center - 10, 50, 50])
    upper = numpy.array([center + 10, 255, 255])
    # Threshold the HSV image to get only blue colors
    mask = cv2.inRange(hsv, lower, upper)
    inverted = cv2.bitwise_not(mask)

    blurred = cv2.GaussianBlur(inverted, (5, 5), 0)
    edged = cv2.Canny(blurred, 50, 100)
    dilated = cv2.dilate(edged, None, iterations=1)
    eroded = cv2.erode(dilated, None, iterations=1)

    # find contours in the thresholded image and initialize the shape detector
    contours = cv2.findContours(eroded.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    contours = contours[0] if imutils.is_cv2() else contours[1]

    # Compute the area for a single part to use when setting the threshold and calculating the number of parts within
    # a contour area.
    part_area = part_area(contours)
    # The threshold for a part's area - can't be too much smaller than the part itself.
    threshold = part_area * 0.5

    part_count = 0
    for contour in contours:
        if cv2.contourArea(contour) < threshold:
            continue

        # Sometimes parts are close enough together that they become one in the image.  To battle this, the total area
        # of the contour is divided by the area of a part (derived earlier).
        part_count += int((cv2.contourArea(contour) / part_area) + 0.1)  # this 0.1 "rounds up" slightly and was determined empirically

        # Draw an approximate contour around each detected part to give the user an idea of what the tool has computed.
        epsilon = 0.1 * cv2.arcLength(contour, True)
        approx = cv2.approxPolyDP(contour, epsilon, True)
        cv2.drawContours(image, [approx], -1, (0, 255, 0), 2)

    # Print the part count and show off the processed image.
    print 'Part Count:', part_count
    cv2.imshow("Image", image)
    cv2.waitKey(0)

這是我正在使用的輸入圖像類型的示例: 一些電容器 或這個: 一些電阻器

我目前正在得到這樣的結果: 在此輸入圖像描述

結果清楚地表明,劇本在識別某些部件時遇到了麻煩,而且當部件彼此接觸時,其真正的跟腱似乎就是這樣。

所以我的問題/挑戰是,我該怎么做才能提高這個腳本的可靠性?

該腳本將集成到現有的Python工具中,因此我正在使用Python搜索解決方案。 因為我願意安裝任何第三方庫可能需要的解決方案並不需要是純Python。

如果對象都是相似的類型,則可能更成功地隔離圖像中的單個示例,然后使用特征匹配來檢測它們。

完整的解決方案將超出Stack Overflow的范圍,但我對進展的建議是首先使用您當前的矩形檢索方法以某種方式找到一個或多個“正確”示例。 您可以查找具有預期大小或准確矩形的所有樣本。

一旦您隔離了一些正面示例,請使用一些功能匹配技術來查找其他示例。 你可能需要做很多閱讀,但這是一個潛在的解決方案。

總結是您使用正例來查找要檢測的對象的“特征”。 這些“特征”通常是角落或漸變的變化。 OpenCV包含許多可以使用的方法。

獲得這些功能之后,您可以在OpenCV中查看幾種算法,這些算法將在圖像中搜索所有匹配的功能。 您將需要一個旋轉不變的(可以檢測以不同旋轉排列的相同特征),但您可能不需要縮放不變性(可以在多個尺度上檢測相同的特征)。

我對這種方法的一個顧慮是,你在圖像中搜索的項目非常小。 可能很難找到匹配的良好,一致的功能。

您正在處理2D對象識別問題,有許多可能的方法。 你已經開始使用背景/前景分割,這是好的,因為你可以控制場景(放下背景紙張)。 然而,當物體接觸時,這將始終具有基本限制。 解決問題的簡單方法是:

1)您認為觸摸物體是罕見事件(這是您問題中的一個很好的假設)。 因此,您可以計算每個分割區域的面積,並計算這些區域的中位數,這將為對象的區域提供穩健的估計。 我們稱之為強健估計A(以平方像素為單位)。 如果少於50%的區域對應於觸摸物體,這將是好的。

2)然后,您繼續測量每個分段區域中的對象數量。 讓Ai成為第i個區域。 然后,您可以通過Ni = round(Ai / A)計算每個區域中的對象數。 然后你總和Ni來給你一個對象的總數。

只要滿足以下條件,此方法就可以了:A)觸摸物體不會明顯重疊B)您的側面沒有物體。 如果你這樣做,你可以使用兩個區域估計(側面和平面)來處理這個問題。 如果您可以簡單,那么最好消除這種情況。 C)物體與相機的距離大致相同。 如果不是這種情況,那么對象的區域(以像素為單位)不能通過單個值很好地建模。 D)圖像邊界處沒有部分可見的物體。 E)確保每個圖像中只顯示相同類型的對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM