如何仅提取图像的圆形 ROI 部分并通过在 Python OpenCV GUI 的 Tkinter window 中单击按钮显示圆的半径

How to extract only circular ROI portion of the image and show Radius of the circle with a button click in Tkinter window of Python OpenCV GUI

提取圆形 ROI 并在 Tkinter 标签中显示圆的半径

我正在向该社区的 python 专家寻求帮助。我在整个 Stackexchange 以及 Github 社区中搜索了我的问题。但我没有找到任何有用的东西。 我创建了一个 Tkinter GUI。在此 GUI 中,我可以从目标文件夹上传我的图像。在评估部分Select,我写了一个脚本,通过它我可以自动查看我在圆形部分的ROI区域。 GUI 显示在该问题的底部。

需要帮助部分:我在创建脚本时遇到问题:

  1. 当我点击 上传 ROI 按钮时,只有选定的 ROI 部分 图像的一部分保存在目标文件夹中,即 path = 'Data/images/' + 名称 + '_' + 方法 + ext
  2. 我可以在 Tkinter GUI 的某处查看圆的半径。

def ROI(self, image, method):
    if method == 'ROI':
        image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
        blimage = cv2.medianBlur(image, 15)
        circles = cv2.HoughCircles(blimage, cv2.HOUGH_GRADIENT, 1, 255, param1=100, param2=60, minRadius=0,
                                   maxRadius=0)

        if circles is not None:
            circles = np.uint16(np.around(circles))
            for i in circles[0, :]:
                cv2.circle(image, (i[0], i[1]), i[2], (0, 255, 0), 6)
                cv2.circle(image, (i[0], i[1]), 2, (0, 0, 255), 3)
        cv2.waitKey()

    else:
        print('method is wrong')

    return image

图形界面

更新:

我添加了变量 border 来计算 x1,y1,x2,y2 所以现在它用边界线裁剪。图像显示没有 border 的旧代码的结果。


如果你只有一个圆圈(x,y,r)那么你可以用它来裁剪图片

image = image[y-r:y+r, x-r:x+r]

我在一些圆比图像大的图像上测试它,我不得不使用 int16 而不是 unit16 来获得 -1 而不是 65535 170-171y-r)。添加我不得不使用 min(), max()to get0instead-1`

def ROI(self, image, method):
    if method == 'ROI':
        image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
        blimage = cv2.medianBlur(image, 15)
        circles = cv2.HoughCircles(blimage, cv2.HOUGH_GRADIENT, 1, 255, param1=100, param2=60, minRadius=0,
                                   maxRadius=0)
        if circles is not None:
            #print(circles)

            # need `int` instead of `uint` to correctly calculate `y-r` (to get `-1` instead of `65535`)
            circles = np.int16(np.around(circles)) 

            for x,y,r in circles[0, :]:
                print('x, y, r:', x, y, r)

                border = 6

                cv2.circle(image, (x, y), r, (0, 255, 0), border)
                cv2.circle(image, (x, y), 2, (0, 0, 255), 3)

                height, width = image.shape
                print('height, width:', height, width)

                # calculate region to crop
                x1 = max(x-r - border//2, 0)      # eventually  -(border//2+1)
                x2 = min(x+r + border//2, width)  # eventually  +(border//2+1)
                y1 = max(y-r - border//2, 0)      # eventually  -(border//2+1)
                y2 = min(y+r + border//2, height) # eventually  +(border//2+1)
                print('x1, x2:', x1, x2)
                print('y1, y2:', y1, y2)

                # crop image 
                image = image[y1:y2,x1:x2]
                print('height, width:', image.shape)
    else:
        print('method is wrong')

    return image

对于更多圈子,您必须首先计算用于所有圈子的区域(获取所有圈子的最小值 x-ry-r 和最大值 x+ry+r) 和下一个裁剪图像。

稍后我会尝试使用alpha通道去除圆圈外的背景


用于测试的图像(如果其他人想测试代码)


编辑: 我添加了创建带有白色圆圈的黑色图像以删除背景的代码。

def ROI(self, image, method):
    if method == 'ROI':
        image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
        blimage = cv2.medianBlur(image, 15)
        circles = cv2.HoughCircles(blimage, cv2.HOUGH_GRADIENT, 1, 255, param1=100, param2=60, minRadius=0,
                                   maxRadius=0)
        if circles is not None:
            print(circles)
            circles = np.int16(np.around(circles)) # need int instead of uint to correctly calculate y-r (to get -1 instead of 65535)
            for x,y,r in circles[0, :]:
                print('x, y, r:', x, y, r)
                height, width = image.shape
                print('height, width:', height, width)

                border = 6

                cv2.circle(image, (x, y), r, (0, 255, 0), border)
                cv2.circle(image, (x, y), 2, (0, 0, 255), 3)

                mask = np.zeros(image.shape, np.uint8) # black background
                cv2.circle(mask, (x, y), r, (255), border)  # white mask for black border
                cv2.circle(mask, (x, y), r, (255), -1) # white mask for (filled) circle
                #image = cv2.bitwise_and(image, mask)  # image with black background
                image = cv2.bitwise_or(image, ~mask)  # image with white background

                x1 = max(x-r - border//2, 0)      # eventually  -(border//2+1)
                x2 = min(x+r + border//2, width)  # eventually  +(border//2+1)
                y1 = max(y-r - border//2, 0)      # eventually  -(border//2+1)
                y2 = min(y+r + border//2, height) # eventually  +(border//2+1)
                print('x1, x2:', x1, x2)
                print('y1, y2:', y1, y2)

                image = image[y1:y2,x1:x2]
                print('height, width:', image.shape)
    else:
        print('method is wrong')

    return image