Spaces:
Running
on
Zero
Running
on
Zero
Create trimap_module.py
Browse files- trimap_module.py +164 -0
trimap_module.py
ADDED
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python
|
2 |
+
import cv2, os, sys
|
3 |
+
import numpy as np
|
4 |
+
|
5 |
+
def extractImage(path):
|
6 |
+
# error handller if the intended path is not found
|
7 |
+
image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
|
8 |
+
return image
|
9 |
+
|
10 |
+
def checkImage(image):
|
11 |
+
"""
|
12 |
+
Args:
|
13 |
+
image: input image to be checked
|
14 |
+
Returns:
|
15 |
+
binary image
|
16 |
+
Raises:
|
17 |
+
RGB image, grayscale image, all-black, and all-white image
|
18 |
+
|
19 |
+
"""
|
20 |
+
if len(image.shape) > 2:
|
21 |
+
print("ERROR: non-binary image (RGB)"); sys.exit();
|
22 |
+
|
23 |
+
smallest = image.min(axis=0).min(axis=0) # lowest pixel value: 0 (black)
|
24 |
+
largest = image.max(axis=0).max(axis=0) # highest pixel value: 1 (white)
|
25 |
+
|
26 |
+
if (smallest == 0 and largest == 0):
|
27 |
+
print("ERROR: non-binary image (all black)"); sys.exit()
|
28 |
+
elif (smallest == 255 and largest == 255):
|
29 |
+
print("ERROR: non-binary image (all white)"); sys.exit()
|
30 |
+
elif (smallest > 0 or largest < 255 ):
|
31 |
+
print("ERROR: non-binary image (grayscale)"); sys.exit()
|
32 |
+
else:
|
33 |
+
return True
|
34 |
+
|
35 |
+
class Toolbox:
|
36 |
+
def __init__(self, image):
|
37 |
+
self.image = image
|
38 |
+
|
39 |
+
@property
|
40 |
+
def printImage(self):
|
41 |
+
"""
|
42 |
+
Print image into a file for checking purpose
|
43 |
+
unitTest = Toolbox(image);
|
44 |
+
unitTest.printImage(image);
|
45 |
+
"""
|
46 |
+
f = open("image_results.dat", "w+")
|
47 |
+
for i in range(0, self.image.shape[0]):
|
48 |
+
for j in range(0, self.image.shape[1]):
|
49 |
+
f.write("%d " %self.image[i,j])
|
50 |
+
f.write("\n")
|
51 |
+
f.close()
|
52 |
+
|
53 |
+
@property
|
54 |
+
def displayImage(self):
|
55 |
+
"""
|
56 |
+
Display the image on a window
|
57 |
+
Press any key to exit
|
58 |
+
"""
|
59 |
+
cv2.imshow('Displayed Image', self.image)
|
60 |
+
cv2.waitKey(0)
|
61 |
+
cv2.destroyAllWindows()
|
62 |
+
|
63 |
+
def saveImage(self, title, extension):
|
64 |
+
"""
|
65 |
+
Save as a specific image format (bmp, png, or jpeg)
|
66 |
+
"""
|
67 |
+
cv2.imwrite("{}.{}".format(title,extension), self.image)
|
68 |
+
|
69 |
+
def morph_open(self, image, kernel):
|
70 |
+
"""
|
71 |
+
Remove all white noises or speckles outside images
|
72 |
+
Need to tune the kernel size
|
73 |
+
Instruction:
|
74 |
+
unit01 = Toolbox(image);
|
75 |
+
kernel = np.ones( (9,9), np.uint8 );
|
76 |
+
morph = unit01.morph_open(input_image, kernel);
|
77 |
+
"""
|
78 |
+
bin_open = cv2.morphologyEx(self.image, cv2.MORPH_OPEN, kernel)
|
79 |
+
return bin_open
|
80 |
+
|
81 |
+
def morph_close(self, image, kernel):
|
82 |
+
"""
|
83 |
+
Remove all black noises or speckles inside images
|
84 |
+
Need to tune the kernel size
|
85 |
+
Instruction:
|
86 |
+
unit01 = Toolbox(image);
|
87 |
+
kernel = np.ones( (11,11)_, np.uint8 );
|
88 |
+
morph = unit01.morph_close(input_image, kernel);
|
89 |
+
"""
|
90 |
+
bin_close = cv2.morphologyEx(self.image, cv2.MORPH_CLOSE, kernel)
|
91 |
+
return bin_close
|
92 |
+
|
93 |
+
|
94 |
+
def trimap(image, name, size, number, erosion=False):
|
95 |
+
"""
|
96 |
+
This function creates a trimap based on simple dilation algorithm
|
97 |
+
Inputs [4]: a binary image (black & white only), name of the image, dilation pixels
|
98 |
+
the last argument is optional; i.e., how many iterations will the image get eroded
|
99 |
+
Output : a trimap
|
100 |
+
"""
|
101 |
+
checkImage(image)
|
102 |
+
row = image.shape[0]
|
103 |
+
col = image.shape[1]
|
104 |
+
pixels = 2*size + 1 ## Double and plus 1 to have an odd-sized kernel
|
105 |
+
kernel = np.ones((pixels,pixels),np.uint8) ## Pixel of extension I get
|
106 |
+
|
107 |
+
if erosion is not False:
|
108 |
+
erosion = int(erosion)
|
109 |
+
erosion_kernel = np.ones((3,3), np.uint8) ## Design an odd-sized erosion kernel
|
110 |
+
image = cv2.erode(image, erosion_kernel, iterations=erosion) ## How many erosion do you expect
|
111 |
+
image = np.where(image > 0, 255, image) ## Any gray-clored pixel becomes white (smoothing)
|
112 |
+
# Error-handler to prevent entire foreground annihilation
|
113 |
+
if cv2.countNonZero(image) == 0:
|
114 |
+
print("ERROR: foreground has been entirely eroded")
|
115 |
+
sys.exit()
|
116 |
+
|
117 |
+
dilation = cv2.dilate(image, kernel, iterations = 1)
|
118 |
+
|
119 |
+
dilation = np.where(dilation == 255, 127, dilation) ## WHITE to GRAY
|
120 |
+
remake = np.where(dilation != 127, 0, dilation) ## Smoothing
|
121 |
+
remake = np.where(image > 127, 200, dilation) ## mark the tumor inside GRAY
|
122 |
+
|
123 |
+
remake = np.where(remake < 127, 0, remake) ## Embelishment
|
124 |
+
remake = np.where(remake > 200, 0, remake) ## Embelishment
|
125 |
+
remake = np.where(remake == 200, 255, remake) ## GRAY to WHITE
|
126 |
+
|
127 |
+
#############################################
|
128 |
+
# Ensures only three pixel values available #
|
129 |
+
# TODO: Optimization with Cython #
|
130 |
+
#############################################
|
131 |
+
for i in range(0,row):
|
132 |
+
for j in range (0,col):
|
133 |
+
if (remake[i,j] != 0 and remake[i,j] != 255):
|
134 |
+
remake[i,j] = 127
|
135 |
+
|
136 |
+
path = "./images/results/" ## Change the directory
|
137 |
+
new_name = '{}px_'.format(size) + name + '_{}.png'.format(number)
|
138 |
+
cv2.imwrite(os.path.join(path, new_name) , remake)
|
139 |
+
|
140 |
+
|
141 |
+
#############################################
|
142 |
+
### TESTING SECTION ###
|
143 |
+
#############################################
|
144 |
+
if __name__ == '__main__':
|
145 |
+
path = "./images/test_images/test_image_11.png"
|
146 |
+
image = extractImage(path)
|
147 |
+
|
148 |
+
size = 10
|
149 |
+
number = path[-5]
|
150 |
+
title = "test_image"
|
151 |
+
|
152 |
+
unit01 = Toolbox(image);
|
153 |
+
kernel1 = np.ones( (11,11), np.uint8 )
|
154 |
+
unit01.displayImage
|
155 |
+
|
156 |
+
opening = unit01.morph_close(image,kernel1)
|
157 |
+
trimap(opening, title, size, number, erosion=False)
|
158 |
+
unit02 = Toolbox(opening)
|
159 |
+
unit02.displayImage
|
160 |
+
|
161 |
+
########################################################
|
162 |
+
## Default instruction (no binary opening or closing ##
|
163 |
+
## trimap(image, title, size, number, erosion=False); ##
|
164 |
+
########################################################
|