问题
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:
- 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
- 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 get
0instead
-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