【问题标题】:Detecting object location in image with Python OpenCV使用 Python OpenCV 检测图像中的对象位置
【发布时间】:2020-04-18 20:37:19
【问题描述】:

我需要在图像中找到下方肿瘤的位置,即大脑的左侧或右侧。

我尝试使用轮廓和 Canny 边缘检测来检测侧面,但似乎不起作用

# Find Canny edges 
edged = cv2.Canny(img, 30, 200) 
cv2.waitKey(0) 

# Finding Contours 
# Use a copy of the image e.g. edged.copy() 
# since findContours alters the image 
contours, hierarchy = cv2.findContours(edged,  
    cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) 

cv2.imshow('Canny Edges After Contouring', edged) 
cv2.waitKey(0) 

print("Number of Contours found = " + str(len(contours))) 

# Draw all contours 
# -1 signifies drawing all contours 
cv2.drawContours(img, contours, -1, (0, 255, 0), 3) 

【问题讨论】:

    标签: python image opencv image-processing computer-vision


    【解决方案1】:

    一种方法是利用肿瘤颜色较浅的观察结果来执行颜色分割。我们首先提取大脑 ROI,以防万一 大脑与一侧对齐,而不是在图像的中心。从这里将图像转换为 HSV 颜色空间,定义上下颜色范围,然后使用cv2.inRange() 执行颜色阈值处理。这将为我们提供一个二进制掩码。从这里我们只需裁剪蒙版的左右两半,然后使用cv2.countNonZero() 计算每一侧的像素。具有较高像素数的一侧将是有肿瘤的一侧。


    Otsu 的阈值 -> 检测到的大脑 ROI -> 提取的 ROI

    # Load image, grayscale, Otsu's threshold, and extract ROI
    image = cv2.imread('1.jpg')
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    x,y,w,h = cv2.boundingRect(thresh)
    ROI = image[y:y+h, x:x+w]
    

    在提取的 ROI 上进行颜色分割后生成的二进制掩码

    # Color segmentation on ROI
    hsv = cv2.cvtColor(ROI, cv2.COLOR_BGR2HSV)
    lower = np.array([0, 0, 152])
    upper = np.array([179, 255, 255])
    mask = cv2.inRange(hsv, lower, upper)
    

    裁剪左右两半

    # Crop left and right half of mask
    x, y, w, h = 0, 0, image.shape[1]//2, image.shape[0]
    left = mask[y:y+h, x:x+w]
    right = mask[y:y+h, x+w:x+w+w]
    

    每一半的像素数

    左像素:1252

    右像素:12

    # Count pixels
    left_pixels = cv2.countNonZero(left)
    right_pixels = cv2.countNonZero(right)
    

    由于左半边有更多像素,因此肿瘤位于大脑的半边


    完整代码

    import numpy as np
    import cv2
    
    # Load image, grayscale, Otsu's threshold, and extract ROI
    image = cv2.imread('1.jpg')
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    x,y,w,h = cv2.boundingRect(thresh)
    ROI = image[y:y+h, x:x+w]
    
    # Color segmentation on ROI
    hsv = cv2.cvtColor(ROI, cv2.COLOR_BGR2HSV)
    lower = np.array([0, 0, 152])
    upper = np.array([179, 255, 255])
    mask = cv2.inRange(hsv, lower, upper)
    
    # Crop left and right half of mask
    x, y, w, h = 0, 0, ROI.shape[1]//2, ROI.shape[0]
    left = mask[y:y+h, x:x+w]
    right = mask[y:y+h, x+w:x+w+w]
    
    # Count pixels
    left_pixels = cv2.countNonZero(left)
    right_pixels = cv2.countNonZero(right)
    
    print('Left pixels:', left_pixels)
    print('Right pixels:', right_pixels)
    
    cv2.imshow('mask', mask)
    cv2.imshow('thresh', thresh)
    cv2.imshow('ROI', ROI)
    cv2.imshow('left', left)
    cv2.imshow('right', right)
    cv2.waitKey()
    

    我使用这个 HSV 颜色阈值脚本来确定上下颜色范围

    import cv2
    import sys
    import numpy as np
    
    def nothing(x):
        pass
    
    # Create a window
    cv2.namedWindow('image')
    
    # create trackbars for color change
    cv2.createTrackbar('HMin','image',0,179,nothing) # Hue is from 0-179 for Opencv
    cv2.createTrackbar('SMin','image',0,255,nothing)
    cv2.createTrackbar('VMin','image',0,255,nothing)
    cv2.createTrackbar('HMax','image',0,179,nothing)
    cv2.createTrackbar('SMax','image',0,255,nothing)
    cv2.createTrackbar('VMax','image',0,255,nothing)
    
    # Set default value for MAX HSV trackbars.
    cv2.setTrackbarPos('HMax', 'image', 179)
    cv2.setTrackbarPos('SMax', 'image', 255)
    cv2.setTrackbarPos('VMax', 'image', 255)
    
    # Initialize to check if HSV min/max value changes
    hMin = sMin = vMin = hMax = sMax = vMax = 0
    phMin = psMin = pvMin = phMax = psMax = pvMax = 0
    
    img = cv2.imread('1.jpg')
    output = img
    waitTime = 33
    
    while(1):
    
        # get current positions of all trackbars
        hMin = cv2.getTrackbarPos('HMin','image')
        sMin = cv2.getTrackbarPos('SMin','image')
        vMin = cv2.getTrackbarPos('VMin','image')
    
        hMax = cv2.getTrackbarPos('HMax','image')
        sMax = cv2.getTrackbarPos('SMax','image')
        vMax = cv2.getTrackbarPos('VMax','image')
    
        # Set minimum and max HSV values to display
        lower = np.array([hMin, sMin, vMin])
        upper = np.array([hMax, sMax, vMax])
    
        # Create HSV Image and threshold into a range.
        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
        mask = cv2.inRange(hsv, lower, upper)
        output = cv2.bitwise_and(img,img, mask= mask)
    
        # Print if there is a change in HSV value
        if( (phMin != hMin) | (psMin != sMin) | (pvMin != vMin) | (phMax != hMax) | (psMax != sMax) | (pvMax != vMax) ):
            print("(hMin = %d , sMin = %d, vMin = %d), (hMax = %d , sMax = %d, vMax = %d)" % (hMin , sMin , vMin, hMax, sMax , vMax))
            phMin = hMin
            psMin = sMin
            pvMin = vMin
            phMax = hMax
            psMax = sMax
            pvMax = vMax
    
        # Display output image
        cv2.imshow('image',output)
    
        # Wait longer to prevent freeze for videos.
        if cv2.waitKey(waitTime) & 0xFF == ord('q'):
            break
    
    cv2.destroyAllWindows()
    

    【讨论】:

    • 你提到的方法真的很有帮助。你认为如果大脑对齐到一侧而不是在 jpg 图像的中心,这可以工作吗?
    • @ShaviPathirana 检查更新,如果大脑在图像中的任何位置对齐,它现在应该可以工作。它不必位于图像的中心。唯一的假设是每张图像只有一个大脑
    • 使用 otsu 阈值比使用普通阈值是否有特定原因
    • 是的 Otsu 会自动计算阈值,因此如果照明条件发生变化,它将正确适应。您也可以尝试自适应阈值。见here
    【解决方案2】:

    cannyfindContours 不是解决此类问题的好方法。如果您想要一个简单的解决方案,只需使用阈值方法。大津阈值也会给你一个很好的结果。

    【讨论】:

    • 请注意,由于存在三个主要级别(黑色背景、灰色组织和白色肿瘤,Otsu 可能会选择错误的阈值。
    • @YvesDaoust 黑色背景可以通过在数组中放置非零像素并在该数组上执行 Otsu 来忽略。此外,这是最简单的方法而不是最好的方法。可以通过主动轮廓等更复杂的方法来完成。
    猜你喜欢
    • 2016-04-02
    • 2020-12-03
    • 1970-01-01
    • 1970-01-01
    • 2017-03-18
    • 2018-06-16
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多