import cv2
import numpy as np
# Initialize global variables
drawing =False# True if the mouse is pressed
mode ='rectangle'# 'rectangle', 'circle', 'ellipse', or 'freehand'
ix, iy =-1,-1# Initial position
rois =[]# List to store drawn ROIs
selected_roi_index =-1# Index of the selected ROI for dragging
resizing =False# True if resizing an ROI
points =[]# List to store points for freehand drawing# Mouse callback functiondefdraw_shape(event, x, y, flags, param):global ix, iy, drawing, mode, points
if event == cv2.EVENT_LBUTTONDOWN:if mode =='freehand':
drawing =True
ix, iy = x, y
points.append((x, y))else:
drawing =True
ix, iy = x, y
elif event == cv2.EVENT_MOUSEMOVE:if drawing:if mode =='freehand':
points.append((x, y))
temp_image = cv2.cvtColor(image_np.copy(), cv2.COLOR_GRAY2BGR)
draw_current_roi(temp_image, x, y)
draw_all_rois(temp_image)
cv2.imshow('image', temp_image)else:
temp_image = cv2.cvtColor(image_np.copy(), cv2.COLOR_GRAY2BGR)
draw_current_roi(temp_image, x, y)
draw_all_rois(temp_image)
cv2.imshow('image', temp_image)elif event == cv2.EVENT_LBUTTONUP:
drawing =Falseif mode =='freehand':
points.append((x, y))
add_roi('freehand', points)
points =[]else:
add_roi(mode,(ix, iy),(x, y))
update_output_image()
display_final_image()defdraw_current_roi(image, x, y):if mode =='rectangle':
cv2.rectangle(image,(ix, iy),(x, y),(0,0,255),1)# Red color for rectangleselif mode =='circle':
radius =int(((x - ix)**2+(y - iy)**2)**0.5)
cv2.circle(image,(ix, iy), radius,(0,0,255),1)# Red color for circleselif mode =='ellipse':
cv2.ellipse(image,((ix + x)//2,(iy + y)//2),(abs(x - ix)//2,abs(y - iy)//2),0,0,360,(0,0,255),1)# Red color for ellipsesdefdraw_all_rois(image):for roi in rois:if roi[0]=='rectangle':
cv2.rectangle(image, roi[1], roi[2],(0,0,255),1)elif roi[0]=='circle':
cv2.circle(image, roi[1],int(roi[2]),(0,0,255),1)elif roi[0]=='ellipse':
cv2.ellipse(image, roi[1], roi[2], roi[3],0,360,(0,0,255),1)elif roi[0]=='freehand':
cv2.polylines(image,[np.array(roi[1])],False,(0,0,255),1)defadd_roi(roi_type,*args):if roi_type =='rectangle':
roi =(roi_type, args[0], args[1])elif roi_type =='circle':
center = args[0]
edge = args[1]
radius =int(((edge[0]- center[0])**2+(edge[1]- center[1])**2)**0.5)
roi =(roi_type, center, radius)elif roi_type =='ellipse':
roi =(roi_type, args[0], args[1], args[2])elif roi_type =='freehand':
roi =(roi_type, args[0])
rois.append(roi)defupdate_output_image():global output_image
output_image[:]= np.zeros_like(image_np)for roi in rois:if roi[0]=='rectangle':
cv2.rectangle(output_image, roi[1], roi[2],255,-1)elif roi[0]=='circle':
cv2.circle(output_image, roi[1], roi[2],255,-1)elif roi[0]=='ellipse':
cv2.ellipse(output_image, roi[1], roi[2], roi[3],0,360,255,-1)elif roi[0]=='freehand':
cv2.fillPoly(output_image,[np.array(roi[1])],255)defdisplay_final_image():
display_image = cv2.cvtColor(image_np.copy(), cv2.COLOR_GRAY2BGR)
draw_all_rois(display_image)
cv2.imshow('image', display_image)# Load the original image as grayscale
image_path ='*.bmp'# Replace with your image path
image_np = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)# Create an all-black mask with the same size as the original image
output_image = np.zeros_like(image_np)# Create a window and set a mouse callback
cv2.namedWindow('image', cv2.WINDOW_NORMAL)# Create a resizable window
cv2.resizeWindow('image', image_np.shape[1], image_np.shape[0])# Resize window to fit the image
cv2.setMouseCallback('image', draw_shape)print("Press 'r' to switch to rectangle mode.")print("Press 'c' to switch to circle mode.")print("Press 'e' to switch to ellipse mode.")print("Press 'f' to switch to freehand mode.")print("Press 'q' to quit.")# Display the original image
cv2.imshow('image', image_np)whileTrue:
key = cv2.waitKey(1)&0xFFif key ==ord('q'):breakelif key ==ord('r'):
mode ='rectangle'elif key ==ord('c'):
mode ='circle'elif key ==ord('e'):
mode ='ellipse'elif key ==ord('f'):
mode ='freehand'# Save the final mask as a grayscale single-channel image
mask_filename ='output_mask.png'
cv2.imwrite(mask_filename, output_image)# Cleanup
cv2.destroyAllWindows()