-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcrop.py
146 lines (114 loc) · 4.82 KB
/
crop.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
##########################################################
##########################################################
#
# crop.py
# crops and exports slide image
#
# USAGE
# 1. python crop.py [filename] [extension]
# 2. drag to select area for export
# 3. press ENTER(RETURN) to export image
# 4. press ESC to close application
#
# [[ THIS IS A PROJECT OF DEVDOCTORS ]]
# [[ https://bit.ly/devdoctors ]]
#
# Created by JoonNyung Heo (github @jnheo-md)
# jnheo@jnheo.com
# https://jnheo.com
#
##########################################################
##########################################################
from openslide import OpenSlide
import cv2
import numpy as np
import sys
################################
# Draws rectangle on the image
################################
def draw_rectangle(x,y):
global small_img, image
image = small_img.copy() # start from original image
image -= 50 # decrease brightness of image
dragged = np.zeros_like(image)
cv2.rectangle(dragged, pt1=(ix,iy), pt2=(x, y),color=(255,255,255),thickness=-1) # create white box
alpha = 0.8
mask = dragged.astype(bool)
image[mask] = cv2.addWeighted(image, alpha, dragged, 1-alpha,0)[mask] # merge rectangle onto image
def onClick(event, x, y, flags, param):
global ix, iy, drawing, finalX, finalY
if event == cv2.EVENT_LBUTTONDOWN: #when mousedown, set initial values
drawing = True
ix = x
iy = y
elif event == cv2.EVENT_MOUSEMOVE: #when moving, redraw rectangle
if drawing == True:
draw_rectangle(x,y)
elif event == cv2.EVENT_LBUTTONUP: #when dragging end, set drawing to false and save the final coordinates
drawing = False
finalX = x
finalY = y
if abs(x-ix)<10 and abs(y-iy)<10 : # if dragged are is too small, ignore
return
draw_rectangle(x,y)
###### START ######
if len(sys.argv) == 1:
# no argument so error
print("")
print("=====================================================")
print("!!!!! ERROR : Please provide the slide file !!!!!!!!!")
print("-----------------------------------------------------")
print(" USAGE")
print("-----------------------------------------------------")
print("python crop.py [filename] [extension, default to tif]")
print("ex) python crop.py filename.svs png")
print("=====================================================")
print("")
exit()
if len(sys.argv) > 2: #receives second argument as output image extension (ex .tif)
FILE_EXT = sys.argv[2]
else : # Default extension to tif
FILE_EXT = "tif"
FILE_NAME = sys.argv[1] #receives first argument as input file
slide_img = OpenSlide(FILE_NAME)
small_level = 2 #use small image for setting croppable area
if slide_img.level_count <= 2: small_level = slide_img.level_count-1 # if there is less than or equal to 2 levels, set level to last level
small_img_size = slide_img.level_dimensions[small_level]
small_img = np.array(slide_img.read_region((0,0), small_level, size=small_img_size))
small_img = cv2.cvtColor(small_img, cv2.COLOR_RGB2BGR) #finally, the image is presentable with cv2.imshow
#variables for dragging, initial values
ix = -1
iy = -1
finalX = -1
finalY = -1
drawing = False
image = small_img.copy() #image for displaying
WINDOW_NAME = "DRAG to set crop area, then press ENTER"
cv2.namedWindow(WINDOW_NAME)
cv2.setMouseCallback(WINDOW_NAME, onClick)
while True:
cv2.imshow(WINDOW_NAME, image)
ret = cv2.waitKey(10)
if ret == 27: #esc, exit
exit()
elif ret==13 : #return, so continue!
cv2.destroyAllWindows()
print("Cropping and exporting image...")
break
if abs(ix-finalX) < 10 and abs(iy-finalY) < 10 : # no area or too small area was selected. so export whole image
ix = 0
iy =0
finalX = small_img_size[0]
finalY = small_img_size[1]
del small_img #will not use again
# we got the coordinates to crop!
# so crop then save to the specified file format
orig_img_size = slide_img.level_dimensions[0] #get full resolution image size
resize_ratio = orig_img_size[0]/small_img_size[0] # get the ratio of larger image compared to thumbnail
newX1 = int(resize_ratio*ix) #start X of new image
newY1 = int(resize_ratio*iy) #start Y of new image
newX2 = int(resize_ratio*finalX) #end X of new image
newY2 = int(resize_ratio*finalY) #end Y of new image
image = np.array(slide_img.read_region((newX1,newY1), 0,size = (newX2-newX1, newY2-newY1)))
image = cv2.cvtColor(image,cv2.COLOR_RGB2BGR)
cv2.imwrite(FILE_NAME+"."+FILE_EXT,image) #finally, right to file with extension