Newer
Older
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#!/usr/bin/env python
"""
A module for generating test plates and overlays for the screening version of openBIS
"""
import canvas
import math
import os
import shutil
import string
def generate_tile_description(tile, time = None, depth = None):
"""
Generate a description for the combination of well, tile, channel
and, optionaly, depth and/or time
"""
desc = "s"+ str(tile)
if depth is not None:
desc = desc + "_z" + str(depth)
if time is not None:
desc = desc + "_t" + str(time)
return desc
def generate_file_name(well, channel, desc):
"""
Generate a name for a file using the description and channel
"""
return "bPLATE_w" + well + "_" + desc + "_c" + channel + ".png"
def drawRect(canvas, r, g, b, start, isUnfilled = 0):
canvas.draw_inset_rect(r, g, b, start, isUnfilled)
def drawText(canvas, x, y, text):
canvas.draw_text(x, y, text)
def calcTile(coords):
x,y = coords
return (y-1)*3+x
class ImageGeneratorConfig:
"""
Represents the configuration options for generating images
"""
def __init__(self):
self.number_of_tiles = 9
self.image_size = 512
self.is_split = False
# Use an array with None for not time points / depth points
self.time_points = [ None ]
self.depth_points = [ None ]
self.tile_description_generator = generate_tile_description
self.file_name_generator = generate_file_name
class PlateGeneratorConfig(ImageGeneratorConfig):
"""
Represents the configuration options for generating plates
"""
def __init__(self):
ImageGeneratorConfig.__init__(self)
self.rows = 8
self.cols = 12
class WellGenerator:
"""
A class that generates raw images or overlays for a well. Used by the PlateGenerator and ImageGenerator.
"""
def __init__(self, config, well, directory):
"""Constructor that takes the config and the well we are generating images for."""
self.config = config
self.well = well
self.directory = directory
def generate_raw_images(self):
for tile in range(1, self.config.number_of_tiles + 1):
for time in self.config.time_points:
for depth in self.config.depth_points:
desc = self.config.tile_description_generator(tile, time, depth)
if self.config.is_split:
file_name = self.config.file_name_generator(self.well, "RED", desc)
self._generate_tile(file_name, desc, 1, 0, 0)
file_name = self.config.file_name_generator(self.well, "GREEN", desc)
self._generate_tile(file_name, desc, 0, 1, 0)
file_name = self.config.file_name_generator(self.well, "BLUE", desc)
self._generate_tile(file_name, desc, 0, 0, 1)
else:
file_name = self.config.file_name_generator(self.well, "RGB", desc)
self._generate_tile(file_name, desc, 1, 1, 1)
def _generate_tile(self, filename, tile_desc, r, g, b):
tile_canvas = canvas.TileCanvas(self.config.image_size, self.config.image_size)
drawRect(tile_canvas, 0, 0, 0, 0) # fill with black
if self.config.is_split:
# if split, we want to draw white instead of the specified color, since
# the channel assignment will happen in openBIS, not here
if r:
drawRect(tile_canvas, 1, 1, 1, 20) # red
if g:
drawRect(tile_canvas, 1, 1, 1, 70) # green
if b:
drawRect(tile_canvas, 1, 1, 1, 120) # blue
else:
drawRect(tile_canvas, 1, 0, 0, 20) # red
drawRect(tile_canvas, 0, 1, 0, 70) # green
drawRect(tile_canvas, 0, 0, 1, 120) # blue
# text annotation
drawText(tile_canvas, 5, self.config.image_size / 2, tile_desc)
drawText(tile_canvas, 5, 5, self.well)
# Write the bitmap to disk in PNG format
tile_canvas.write_png_file(self.directory + "/" + filename)
def drawMatrix(self, coordsList, dir, channel, isOverlay):
nonemptyTiles = set([ calcTile(coords) for coords in coordsList ])
for tile in range(1, 10):
imageCanvas = canvas.TileCanvas(self.config.image_size, self.config.image_size)
if tile in nonemptyTiles:
if not isOverlay:
drawRect(imageCanvas, 0, 0, 0, 0)
drawRect(imageCanvas, 0.5, 0.5, 0.5, 70, isUnfilled = 0)
elif isOverlay == 1:
drawRect(imageCanvas, 1, 1, 1, 30, isUnfilled = 1)
else:
drawText(imageCanvas, size/2, size/2, "X")
destFile = dir + "/c"+channel + "_s" + str(tile) +".png"
imageCanvas.write_png_file(destFile)
class PlateGenerator:
"""
A class that generates raw images or overlays for a plate.
To use, instantiate it with a PlateGeneratorConfig that describes its properties, then
call generate_raw_images or generate_overlays
"""
def __init__(self, config):
"""Constructor that takes the configuration for the plate"""
self.config = config
def generate_raw_images(self, directory):
for row in range(0, self.config.rows):
for col in range(1, self.config.cols + 1):
well = string.letters[26 + row] + str(col)
well_generator = WellGenerator(self.config, well, directory)
well_generator.generate_raw_images()
def overlayTests(sampleCode):
rootDir = "targets/generated-images"
recreateDir(rootDir)
dir = rootDir + "/" + sampleCode+".basic"
recreateDir(dir)
drawMatrix(((1,1), (1,2), (1,3), (3,1)), dir, "NUCLEUS", 0);
drawMatrix(((1,2), (2,2), (2,3), (3,1)), dir, "CELL", 0);
drawMatrix(((1,3), (2,3), (3,3), (3,1)), dir, "MITOCHONDRION", 0);
dir = rootDir + "/" + sampleCode+".overlay-surround"
recreateDir(dir)
drawMatrix(((1,1), (1,2), (1,3), (3,1)), dir, "NUCLEUS", 1);
drawMatrix(((1,2), (2,2), (2,3), (3,1)), dir, "CELL", 1);
drawMatrix(((1,3), (2,3), (3,3), (3,1)), dir, "MITOCHONDRION", 1);
dir = rootDir + "/" + sampleCode+".overlay-text"
recreateDir(dir)
drawMatrix(((1,1), (1,2), (1,3), (3,1)), dir, "NUCLEUS-TEXT", 2);
drawMatrix(((1,2), (2,2), (2,3), (3,1)), dir, "CELL-TEXT", 2);
drawMatrix(((1,3), (2,3), (3,3), (3,1)), dir, "MITOCHONDRION-TEXT", 2);
def recreateDir(dir):
if os.path.exists(dir):
shutil.rmtree(dir)
os.mkdir(dir)
recreateDir("PLATONIC")
config = PlateGeneratorConfig()
# Alternative Configurations
#config.time_points = [ 5, 10, 15 ]
#config.depth_points = [ 3, 6, 9 ]
#config.is_split = True
generator = PlateGenerator(config)
generator.generate_raw_images("PLATONIC")