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

|▌冷眼眸甩不掉的悲伤 提交于 2020-01-06 05:39:06

问题


Extract Circular ROI & Show Radius of the Circle in Tkinter Label

I am requesting help from python experts in this community. I have searched about my problem all over Stackexchange as well as the Github community. But I didn't find anything helpful. I have created a Tkinter GUI. In this GUI, I can upload my image from the destination folder. In Select of the evaluation section, I have written a script through which I can automatically view my ROI region in the circular part. The GUI is displayed at the bottom part of this question.

Help required Section: I am having trouble in creating a script through which:

  1. when I click on Upload ROI button, only the selected ROI portion of the image gets saved at the destination folder i.e path = 'Data/images/' + name + '_' + method + ext
  2. I can view the Radius of the circle somewhere on the the 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

GUI


回答1:


UPDATE:

I added variable border to calculate x1,y1,x2,y2 so now it crops with borderline. Images show results for old code without border.


If you have only one circle (x,y,r) then you can use it to crop image

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

I test it on some image with circle bigger then image and I had to use int16 instead of unit16 to get -1 instead of 65535 for 170-171 (y-r). Add I had to use 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

For more circles you would have to first calculate region used for all circles (get drom all circles minimal values x-r,y-r and maximal values x+r,y+r) and next crop image.

Later I will try to use alpha channel to remove backgroud outside circle.


Image used for test (if someone else would like to test code)


EDIT: I added code which create black image with white circle to remove background.

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



来源:https://stackoverflow.com/questions/59477313/how-to-extract-only-circular-roi-portion-of-the-image-and-show-radius-of-the-cir

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!