Package omero :: Package util :: Module script_utils
[hide private]
[frames] | no frames]

Source Code for Module omero.util.script_utils

   1  # 
   2  # 
   3  #------------------------------------------------------------------------------ 
   4  #  Copyright (C) 2006-2009 University of Dundee. All rights reserved. 
   5  # 
   6  # 
   7  #   This program is free software; you can redistribute it and/or modify 
   8  #  it under the terms of the GNU General Public License as published by 
   9  #  the Free Software Foundation; either version 2 of the License, or 
  10  #  (at your option) any later version. 
  11  #  This program is distributed in the hope that it will be useful, 
  12  #  but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13  #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  14  #  GNU General Public License for more details. 
  15  # 
  16  #  You should have received a copy of the GNU General Public License along 
  17  #  with this program; if not, write to the Free Software Foundation, Inc., 
  18  #  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
  19  # 
  20  #------------------------------------------------------------------------------ 
  21  ### 
  22  # 
  23  # Utility methods for deal with scripts. 
  24  # 
  25  # @author  Jean-Marie Burel      
  26  #   <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a> 
  27  # @author   Donald MacDonald &nbsp;&nbsp;&nbsp;&nbsp; 
  28  #   <a href="mailto:donald@lifesci.dundee.ac.uk">donald@lifesci.dundee.ac.uk</a> 
  29  # @author   Will Moore &nbsp;&nbsp;&nbsp;&nbsp; 
  30  #   <a href="mailto:will@lifesci.dundee.ac.uk">will@lifesci.dundee.ac.uk</a> 
  31  # @version 3.0 
  32  # <small> 
  33  # (<b>Internal version:</b> $Revision: $Date: $) 
  34  # </small> 
  35  # @since 3.0-Beta4 
  36  # 
  37   
  38  import logging 
  39  import getopt, sys, os, subprocess 
  40  from struct import * 
  41   
  42  import omero.clients 
  43  import omero_Constants_ice 
  44  from omero.rtypes import * 
  45  import omero.util.pixelstypetopython as pixelstypetopython 
  46  from omero.util.OmeroPopo import EllipseData as EllipseData 
  47  from omero.util.OmeroPopo import RectData as RectData 
  48  from omero.util.OmeroPopo import MaskData as MaskData 
  49  from omero.util.OmeroPopo import WorkflowData as WorkflowData 
  50  from omero.util.OmeroPopo import ROIData as ROIData 
  51   
  52   
  53  try: 
  54      import hashlib 
  55      hash_sha1 = hashlib.sha1 
  56  except: 
  57      import sha 
  58      hash_sha1 = sha.new 
  59   
  60  # r,g,b,a colours for use in scripts. 
  61  COLOURS = {'Red': (255,0,0,255), 'Green': (0,255,0,255), 'Blue': (0,0,255,255), 'Yellow': (255,255,0,255), 
  62      'White': (255,255,255,255), } 
  63   
  64  EXTRA_COLOURS = {'Violet': (238,133,238,255), 'Indigo': (79,6,132,255), 
  65      'Black': (0,0,0,255), 'Orange': (254,200,6,255), 'Gray': (130,130,130,255),} 
  66   
  67  CSV_NS = 'text/csv'; 
  68  CSV_FORMAT = 'text/csv'; 
  69  SU_LOG = logging.getLogger("omero.util.script_utils") 
  70   
71 -def drawTextOverlay(draw, x, y, text, colour='0xffffff'):
72 """ 73 Draw test on image. 74 @param draw The PIL Draw class. 75 @param x The x-coord to draw. 76 @param y The y-coord to draw. 77 @param text The text to render. 78 @param colour The colour as a PIL colour string to draw the text in. 79 """ 80 draw.text((x,y),text, fill=colour)
81
82 -def drawLineOverlay(draw, x0, y0, x1, y1, colour='0xffffff'):
83 """ 84 Draw line on image. 85 @param draw The PIL Draw class. 86 @param x0 The x0-coord of line. 87 @param y0 The y0-coord of line. 88 @param x1 The x1-coord of line. 89 @param y1 The y1-coord of line. 90 @param colour The colour as a PIL colour string to draw the text in. 91 """ 92 draw.line([(x0, y0),(x1,y1)], text, fill=colour)
93
94 -def rgbToRGBInt(red, green, blue):
95 """ 96 Convert an R,G,B value to an int. 97 @param R the Red value. 98 @param G the Green value. 99 @param B the Blue value. 100 @return See above. 101 """ 102 RGBInt = (red<<16)+(green<<8)+blue; 103 return int(RGBInt);
104
105 -def RGBToPIL(RGB):
106 """ 107 Convert an RGB value to a PIL colour value. 108 @param RGB the RGB value. 109 @return See above. 110 """ 111 hexval = hex(int(RGB)); 112 return '#'+(6-len(hexval[2:]))*'0'+hexval[2:];
113
114 -def rangeToStr(range):
115 """ 116 Map a range to a string of numbers 117 @param range See above. 118 @return See above. 119 """ 120 first = 1; 121 string = ""; 122 for value in range: 123 if(first==1): 124 string = str(value); 125 first = 0; 126 else: 127 string = string + ','+str(value) 128 return string;
129
130 -def rmdir_recursive(dir):
131 for name in os.listdir(dir): 132 full_name = os.path.join(dir, name) 133 # on Windows, if we don't have write permission we can't remove 134 # the file/directory either, so turn that on 135 if not os.access(full_name, os.W_OK): 136 os.chmod(full_name, 0600) 137 if os.path.isdir(full_name): 138 rmdir_recursive(full_name) 139 else: 140 os.remove(full_name) 141 os.rmdir(dir)
142
143 -def calcSha1(filename):
144 """ 145 Returns a hash of the file identified by filename 146 147 @param filename: pathName of the file 148 @return: The hash of the file 149 """ 150 151 fileHandle = open(filename) 152 h = hash_sha1() 153 h.update(fileHandle.read()) 154 hash = h.hexdigest() 155 fileHandle.close() 156 return hash;
157
158 -def calcSha1FromData(data):
159 """ 160 Calculate the Sha1 Hash from a data array 161 @param data The data array. 162 @return The Hash 163 """ 164 h = hash_sha1() 165 h.update(data) 166 hash = h.hexdigest() 167 return hash;
168
169 -def getFormat(queryService, format):
170 return queryService.findByQuery("from Format as f where f.value='"+format+"'", None)
171 172
173 -def createFile(updateService, filename, mimetype=None, origFilePathName=None):
174 """ 175 Creates an original file, saves it to the server and returns the result 176 177 @param queryService: The query service E.g. session.getQueryService() 178 @param updateService: The update service E.g. session.getUpdateService() 179 @param filename: The file path and name (or name if in same folder). String 180 @param mimetype: The mimetype (string) or Format object representing the file format 181 @param origFilePathName: Optional path/name for the original file 182 @return: The saved OriginalFileI, as returned from the server 183 """ 184 185 originalFile = omero.model.OriginalFileI(); 186 if(origFilePathName == None): 187 origFilePathName = filename; 188 path, name = os.path.split(origFilePathName) 189 originalFile.setName(omero.rtypes.rstring(name)); 190 originalFile.setPath(omero.rtypes.rstring(path)); 191 # just in case we are passed a FormatI object 192 try: 193 v = mimetype.getValue() 194 mt = v.getValue() 195 except: 196 # handle the string we expect 197 mt = mimetype 198 if mt: 199 originalFile.mimetype = omero.rtypes.rstring(mt) 200 originalFile.setSize(omero.rtypes.rlong(os.path.getsize(filename))); 201 originalFile.setSha1(omero.rtypes.rstring(calcSha1(filename))); 202 return updateService.saveAndReturnObject(originalFile);
203 204
205 -def uploadFile(rawFileStore, originalFile, filePath=None):
206 """ 207 Uploads an OriginalFile to the server 208 209 @param rawFileStore: The Omero rawFileStore 210 @param originalFile: The OriginalFileI 211 @param filePath: Where to find the file to upload. If None, use originalFile.getName().getValue() 212 """ 213 rawFileStore.setFileId(originalFile.getId().getValue()); 214 fileSize = originalFile.getSize().getValue(); 215 increment = 10000; 216 cnt = 0; 217 if filePath == None: 218 filePath = originalFile.getName().getValue() 219 fileHandle = open(filePath, 'rb'); 220 done = 0 221 while(done!=1): 222 if(increment+cnt<fileSize): 223 blockSize = increment; 224 else: 225 blockSize = fileSize-cnt; 226 done = 1; 227 fileHandle.seek(cnt); 228 block = fileHandle.read(blockSize); 229 rawFileStore.write(block, cnt, blockSize); 230 cnt = cnt+blockSize; 231 fileHandle.close();
232 233
234 -def downloadFile(rawFileStore, originalFile, filePath=None):
235 """ 236 Downloads an OriginalFile from the server. 237 238 @param rawFileStore: The Omero rawFileStore 239 @param originalFile: The OriginalFileI 240 @param filePath: Where to download the file. If None, use originalFile.getName().getValue() 241 """ 242 fileId = originalFile.getId().getValue() 243 rawFileStore.setFileId(fileId) 244 fileSize = originalFile.getSize().getValue() 245 maxBlockSize = 10000 246 cnt = 0 247 if filePath == None: 248 filePath = originalFile.getName().getValue() 249 # don't overwrite. Add number before extension 250 i = 1 251 path, ext = filePath.rsplit(".", 1) 252 while os.path.exists(filePath): 253 filePath = "%s_%s.%s" % (path,i,ext) 254 i +=1 255 fileHandle = open(filePath, 'w') 256 data = ''; 257 cnt = 0; 258 fileSize = originalFile.getSize().getValue() 259 while(cnt<fileSize): 260 blockSize = min(maxBlockSize, fileSize) 261 block = rawFileStore.read(cnt, blockSize) 262 cnt = cnt+blockSize 263 fileHandle.write(block) 264 fileHandle.close() 265 return filePath
266 267
268 -def attachFileToParent(updateService, parent, originalFile, description=None, namespace=None):
269 """ 270 Attaches the original file (file) to a Project, Dataset or Image (parent) 271 272 @param updateService: The update service 273 @param parent: A ProjectI, DatasetI or ImageI to attach the file to 274 @param originalFile: The OriginalFileI to attach 275 @param description: Optional description for the file annotation. String 276 @param namespace: Optional namespace for file annotataion. String 277 @return: The saved and returned *AnnotationLinkI (* = Project, Dataset or Image) 278 """ 279 fa = omero.model.FileAnnotationI(); 280 fa.setFile(originalFile); 281 if description: 282 fa.setDescription(omero.rtypes.rstring(description)) 283 if namespace: 284 fa.setNs(omero.rtypes.rstring(namespace)) 285 if type(parent) == omero.model.DatasetI: 286 l = omero.model.DatasetAnnotationLinkI() 287 elif type(parent) == omero.model.ProjectI: 288 l = omero.model.ProjectAnnotationLinkI() 289 elif type(parent) == omero.model.ImageI: 290 l = omero.model.ImageAnnotationLinkI() 291 else: 292 return 293 parent = parent.__class__(parent.id.val, False) # use unloaded object to avoid update conflicts 294 l.setParent(parent); 295 l.setChild(fa); 296 return updateService.saveAndReturnObject(l);
297 298
299 -def uploadAndAttachFile(queryService, updateService, rawFileStore, parent, localName, mimetype, description=None, namespace=None, origFilePathName=None):
300 """ 301 Uploads a local file to the server, as an Original File and attaches it to the 302 parent (Project, Dataset or Image) 303 304 @param queryService: The query service 305 @param updateService: The update service 306 @param rawFileStore: The rawFileStore 307 @param parent: The ProjectI or DatasetI or ImageI to attach file to 308 @param localName: Full Name (and path) of the file location to upload. String 309 @param mimetype: The original file mimetype. E.g. "PNG". String 310 @param description: Optional description for the file annotation. String 311 @param namespace: Namespace to set for the original file 312 @param origFilePathName: The /path/to/file/fileName.ext you want on the server. If none, use output as name 313 @return: The originalFileLink child. (FileAnnotationI) 314 """ 315 316 filename = localName 317 if origFilePathName == None: 318 origFilePathName = localName 319 originalFile = createFile(updateService, filename, mimetype, origFilePathName); 320 uploadFile(rawFileStore, originalFile, localName) 321 fileLink = attachFileToParent(updateService, parent, originalFile, description, namespace) 322 return fileLink.getChild()
323 324
325 -def addAnnotationToImage(updateService, image, annotation):
326 """ 327 Add the annotation to an image. 328 @param updateService The update service to create the annotation link. 329 @param image The ImageI object that should be annotated. 330 @param annotation The annotation object 331 @return The new annotationlink object 332 """ 333 l = omero.model.ImageAnnotationLinkI(); 334 l.setParent(image); 335 l.setChild(annotation); 336 return updateService.saveAndReturnObject(l);
337
338 -def readFromOriginalFile(rawFileService, iQuery, fileId, maxBlockSize = 10000):
339 """ 340 Read the OriginalFile with fileId and return it as a string. 341 @param rawFileService The RawFileService service to read the originalfile. 342 @param iQuery The Query Service. 343 @param fileId The id of the originalFile object. 344 @param maxBlockSize The block size of each read. 345 @return The OriginalFile object contents as a string 346 """ 347 fileDetails = iQuery.findByQuery("from OriginalFile as o where o.id = " + str(fileId) , None); 348 rawFileService.setFileId(fileId); 349 data = ''; 350 cnt = 0; 351 fileSize = fileDetails.getSize().getValue(); 352 while(cnt<fileSize): 353 blockSize = min(maxBlockSize, fileSize); 354 block = rawFileService.read(cnt, blockSize); 355 data = data + block; 356 cnt = cnt+blockSize; 357 return data[0:fileSize];
358
359 -def readFileAsArray(rawFileService, iQuery, fileId, row, col, separator = ' '):
360 """ 361 Read an OriginalFile with id and column separator and return it as an array. 362 @param rawFileService The RawFileService service to read the originalfile. 363 @param iQuery The Query Service. 364 @param fileId The id of the originalFile object. 365 @param row The number of rows in the file. 366 @param col The number of columns in the file. 367 @param sep the column separator. 368 @return The file as an NumPy array. 369 """ 370 from numpy import fromstring, reshape 371 textBlock = readFromOriginalFile(rawFileService, iQuery, fileId); 372 arrayFromFile = fromstring(textBlock,sep = separator); 373 return reshape(arrayFromFile, (row, col));
374
375 -def readFlimImageFile(rawPixelsStore, pixels):
376 """ 377 Read the RawImageFlimFile with fileId and return it as an array [c, x, y] 378 @param rawPixelsStore The rawPixelStore service to get the image. 379 @param pixels The pixels of the image. 380 @return The Contents of the image for z = 0, t = 0, all channels; 381 """ 382 from numpy import zeros 383 sizeC = pixels.getSizeC().getValue(); 384 sizeX = pixels.getSizeX().getValue(); 385 sizeY = pixels.getSizeY().getValue(); 386 id = pixels.getId().getValue(); 387 pixelsType = pixels.getPixelsType().getValue().getValue(); 388 rawPixelsStore.setPixelsId(id , False); 389 cRange = range(0, sizeC); 390 stack = zeros((sizeC, sizeX, sizeY),dtype=pixelstypetopython.toNumpy(pixelsType)); 391 for c in cRange: 392 plane = downloadPlane(rawPixelsStore, pixels, 0, c, 0); 393 stack[c,:,:]=plane; 394 return stack;
395
396 -def downloadPlane(rawPixelsStore, pixels, z, c, t):
397 """ 398 Download the plane [z,c,t] for image pixels. Pixels must have pixelsType loaded. 399 N.B. The rawPixelsStore must have already been initialised by setPixelsId() 400 @param rawPixelsStore The rawPixelStore service to get the image. 401 @param pixels The pixels of the image. 402 @param z The Z-Section to retrieve. 403 @param c The C-Section to retrieve. 404 @param t The T-Section to retrieve. 405 @return The Plane of the image for z, c, t 406 """ 407 from numpy import array 408 rawPlane = rawPixelsStore.getPlane(z, c, t); 409 sizeX = pixels.getSizeX().getValue(); 410 sizeY = pixels.getSizeY().getValue(); 411 pixelsId = pixels.getId().getValue(); 412 pixelType = pixels.getPixelsType().getValue().getValue(); 413 convertType ='>'+str(sizeX*sizeY)+pixelstypetopython.toPython(pixelType); 414 convertedPlane = unpack(convertType, rawPlane); 415 numpyType = pixelstypetopython.toNumpy(pixelType) 416 remappedPlane = array(convertedPlane, numpyType); 417 remappedPlane.resize(sizeY, sizeX); 418 return remappedPlane;
419 420
421 -def getPlaneFromImage(imagePath, rgbIndex=None):
422 """ 423 Reads a local image (E.g. single plane tiff) and returns it as a numpy 2D array. 424 425 @param imagePath Path to image. 426 """ 427 from numpy import asarray 428 try: 429 from PIL import Image # see ticket:2597 430 except ImportError: 431 import Image # see ticket:2597 432 433 i = Image.open(imagePath) 434 a = asarray(i) 435 if rgbIndex == None: 436 return a 437 else: 438 return a[:, :, rgbIndex]
439 440
441 -def uploadDirAsImages(sf, queryService, updateService, pixelsService, path, dataset = None):
442 """ 443 Reads all the images in the directory specified by 'path' and uploads them to OMERO as a single 444 multi-dimensional image, placed in the specified 'dataset' 445 Uses regex to determine the Z, C, T position of each image by name, 446 and therefore determines sizeZ, sizeC, sizeT of the new Image. 447 448 @param path the path to the directory containing images. 449 @param dataset the OMERO dataset, if we want to put images somewhere. omero.model.DatasetI 450 """ 451 452 import re 453 from numpy import zeros 454 455 regex_token = re.compile(r'(?P<Token>.+)\.') 456 regex_time = re.compile(r'T(?P<T>\d+)') 457 regex_channel = re.compile(r'_C(?P<C>.+?)(_|$)') 458 regex_zslice = re.compile(r'_Z(?P<Z>\d+)') 459 460 # assume 1 image in this folder for now. 461 # Make a single map of all images. key is (z,c,t). Value is image path. 462 imageMap = {} 463 channelSet = set() 464 tokens = [] 465 466 # other parameters we need to determine 467 sizeZ = 1 468 sizeC = 1 469 sizeT = 1 470 zStart = 1 # could be 0 or 1 ? 471 tStart = 1 472 473 fullpath = None 474 475 rgb = False 476 # process the names and populate our imagemap 477 for f in os.listdir(path): 478 fullpath = os.path.join(path, f) 479 tSearch = regex_time.search(f) 480 cSearch = regex_channel.search(f) 481 zSearch = regex_zslice.search(f) 482 tokSearch = regex_token.search(f) 483 484 if f.endswith(".jpg"): 485 rgb = True 486 487 if tSearch == None: 488 theT = 0 489 else: 490 theT = int(tSearch.group('T')) 491 492 if cSearch == None: 493 cName = "0" 494 else: 495 cName = cSearch.group('C') 496 497 if zSearch == None: 498 theZ = 0 499 else: 500 theZ = int(zSearch.group('Z')) 501 502 channelSet.add(cName) 503 sizeZ = max(sizeZ, theZ) 504 zStart = min(zStart, theZ) 505 sizeT = max(sizeT, theT) 506 tStart = min(tStart, theT) 507 if tokSearch != None: 508 tokens.append(tokSearch.group('Token')) 509 imageMap[(theZ, cName, theT)] = fullpath 510 511 colourMap = {} 512 if not rgb: 513 channels = list(channelSet) 514 # see if we can guess what colour the channels should be, based on name. 515 for i, c in enumerate(channels): 516 if c == 'rfp': 517 colourMap[i] = (255, 0, 0, 255) 518 if c == 'gfp': 519 colourMap[i] = (0, 255, 0, 255) 520 else: 521 channels = ("red", "green", "blue") 522 colourMap[0] = (255, 0, 0, 255) 523 colourMap[1] = (0, 255, 0, 255) 524 colourMap[2] = (0, 0, 255, 255) 525 526 sizeC = len(channels) 527 528 # use the common stem as the image name 529 imageName = os.path.commonprefix(tokens).strip('0T_') 530 description = "Imported from images in %s" % path 531 SU_LOG.info("Creating image: %s" % imageName) 532 533 # use the last image to get X, Y sizes and pixel type 534 if rgb: 535 plane = getPlaneFromImage(fullpath, 0) 536 else: 537 plane = getPlaneFromImage(fullpath) 538 pType = plane.dtype.name 539 # look up the PixelsType object from DB 540 pixelsType = queryService.findByQuery(\ 541 "from PixelsType as p where p.value='%s'" % pType, None) # omero::model::PixelsType 542 if pixelsType == None and pType.startswith("float"): # e.g. float32 543 pixelsType = queryService.findByQuery(\ 544 "from PixelsType as p where p.value='%s'" % "float", None) # omero::model::PixelsType 545 if pixelsType == None: 546 SU_LOG.warn("Unknown pixels type for: %s" % pType) 547 return 548 sizeY, sizeX = plane.shape 549 550 SU_LOG.debug("sizeX: %s sizeY: %s sizeZ: %s sizeC: %s sizeT: %s" % (sizeX, sizeY, sizeZ, sizeC, sizeT)) 551 552 # code below here is very similar to combineImages.py 553 # create an image in OMERO and populate the planes with numpy 2D arrays 554 channelList = range(sizeC) 555 imageId = pixelsService.createImage(sizeX, sizeY, sizeZ, sizeT, channelList, pixelsType, imageName, description) 556 params = omero.sys.ParametersI() 557 params.addId(imageId) 558 pixelsId = queryService.projection(\ 559 "select p.id from Image i join i.pixels p where i.id = :id",\ 560 params)[0][0].val 561 562 rawPixelStore = sf.createRawPixelsStore() 563 rawPixelStore.setPixelsId(pixelsId, True) 564 try: 565 for theC in range(sizeC): 566 minValue = 0 567 maxValue = 0 568 for theZ in range(sizeZ): 569 zIndex = theZ + zStart 570 for theT in range(sizeT): 571 tIndex = theT + tStart 572 if rgb: 573 c = "0" 574 else: 575 c = channels[theC] 576 if (zIndex, c, tIndex) in imageMap: 577 imagePath = imageMap[(zIndex, c, tIndex)] 578 if rgb: 579 SU_LOG.debug("Getting rgb plane from: %s" % imagePath) 580 plane2D = getPlaneFromImage(imagePath, theC) 581 else: 582 SU_LOG.debug("Getting plane from: %s" % imagePath) 583 plane2D = getPlaneFromImage(imagePath) 584 else: 585 SU_LOG.debug("Creating blank plane for .", theZ, channels[theC], theT) 586 plane2D = zeros((sizeY, sizeX)) 587 SU_LOG.debug("Uploading plane: theZ: %s, theC: %s, theT: %s" % (theZ, theC, theT)) 588 589 uploadPlane(rawPixelStore, plane2D, theZ, theC, theT) 590 minValue = min(minValue, plane2D.min()) 591 maxValue = max(maxValue, plane2D.max()) 592 pixelsService.setChannelGlobalMinMax(pixelsId, theC, float(minValue), float(maxValue)) 593 rgba = None 594 if theC in colourMap: 595 rgba = colourMap[theC] 596 try: 597 renderingEngine = sf.createRenderingEngine() 598 resetRenderingSettings(renderingEngine, pixelsId, theC, minValue, maxValue, rgba) 599 finally: 600 renderingEngine.close() 601 finally: 602 rawPixelStore.close() 603 604 # add channel names 605 pixels = pixelsService.retrievePixDescription(pixelsId) 606 i = 0 607 for c in pixels.iterateChannels(): # c is an instance of omero.model.ChannelI 608 lc = c.getLogicalChannel() # returns omero.model.LogicalChannelI 609 lc.setName(rstring(channels[i])) 610 updateService.saveObject(lc) 611 i += 1 612 613 # put the image in dataset, if specified. 614 if dataset: 615 link = omero.model.DatasetImageLinkI() 616 link.parent = omero.model.DatasetI(dataset.id.val, False) 617 link.child = omero.model.ImageI(imageId, False) 618 updateService.saveAndReturnObject(link) 619 620 return imageId
621 622 623
624 -def uploadCecogObjectDetails(updateService, imageId, filePath):
625 """ 626 Parses a single line of cecog output and saves as a roi. 627 628 Adds a Rectangle (particle) to the current OMERO image, at point x, y. 629 Uses the self.image (OMERO image) and self.updateService 630 """ 631 632 objects = {} 633 roi_ids = [] 634 635 import fileinput 636 for line in fileinput.input([filePath]): 637 638 theZ = 0 639 theT = None 640 x = None 641 y = None 642 643 parts = line.split("\t") 644 names = ("frame", "objID", "primaryClassLabel", "primaryClassName", "centerX", "centerY", "mean", "sd", "secondaryClassabel", "secondaryClassName", "secondaryMean", "secondarySd") 645 values = {} 646 for idx, name in enumerate(names): 647 if len(parts) >= idx: 648 values[name] = parts[idx] 649 650 frame = values["frame"] 651 try: 652 frame = long(frame) 653 except ValueError: 654 SU_LOG.debug("Non-roi line: %s " % line) 655 continue 656 657 theT = frame - 1 658 objID = values["objID"] 659 className = values["primaryClassName"] 660 x = float(values["centerX"]) 661 y = float(values["centerY"]) 662 663 description = "" 664 for name in names: 665 description += ("%s=%s\n" % (name, values.get(name, "(missing)"))) 666 667 if theT and x and y: 668 SU_LOG.debug("Adding point '%s' to frame: %s, x: %s, y: %s" % (className, theT, x, y)) 669 try: 670 shapes = objects[objID] 671 except KeyError: 672 shapes = [] 673 objects[objID] = shapes 674 shapes.append( (theT, className, x, y, values, description) ) 675 676 for object, shapes in objects.items(): 677 678 # create an ROI, add the point and save 679 roi = omero.model.RoiI() 680 roi.setImage(omero.model.ImageI(imageId, False)) 681 roi.setDescription(omero.rtypes.rstring("objID: %s" % object)) 682 683 # create and save a point 684 for shape in shapes: 685 686 theT, className, x, y, values, description = shape 687 688 point = omero.model.PointI() 689 point.cx = rdouble(x) 690 point.cy = rdouble(y) 691 point.theT = rint(theT) 692 point.theZ = rint(0) # Workaround for shoola:ticket:1596 693 if className: 694 point.setTextValue(rstring(className)) # for display only 695 696 # link the point to the ROI and save it 697 roi.addShape(point) 698 699 roi = updateService.saveAndReturnObject(point) 700 roi_ids.append(roi.id.val) 701 702 return roi_ids
703 704
705 -def split_image(client, imageId, dir, unformattedImageName = "tubulin_P037_T%05d_C%s_Z%d_S1.tif", dims = ('T', 'C', 'Z')):
706 """ 707 Splits the image into component planes, which are saved as local tiffs according to unformattedImageName. 708 E.g. myLocalDir/tubulin_P037_T%05d_C%s_Z%d_S1.tif which will be formatted according to dims, E.g. ('T', 'C', 'Z') 709 Channel will be formatted according to channel name, not index. 710 @param rawPixelsStore The rawPixelStore 711 @param queryService 712 @param c The C-Section to retrieve. 713 @param t The T-Section to retrieve. 714 @param imageName the local location to save the image. 715 """ 716 717 unformattedImageName = os.path.join(dir, unformattedImageName) 718 719 session = client.getSession() 720 queryService = session.getQueryService() 721 rawPixelsStore = session.createRawPixelsStore() 722 pixelsService = session.getPixelsService() 723 724 try: 725 from PIL import Image 726 except: 727 import Image 728 729 query_string = "select p from Pixels p join fetch p.image as i join fetch p.pixelsType where i.id='%s'" % imageId 730 pixels = queryService.findByQuery(query_string, None) 731 sizeX = pixels.getSizeX().getValue() 732 sizeY = pixels.getSizeY().getValue() 733 sizeZ = pixels.getSizeZ().getValue() 734 sizeC = pixels.getSizeC().getValue() 735 sizeT = pixels.getSizeT().getValue() 736 rawPixelsStore.setPixelsId(pixels.getId().getValue(), True) 737 738 channelMap = {} 739 cIndex = 0 740 pixels = pixelsService.retrievePixDescription(pixels.id.val) # load channels 741 for c in pixels.iterateChannels(): 742 lc = c.getLogicalChannel() 743 channelMap[cIndex] = lc.getName() and lc.getName().getValue() or str(cIndex) 744 cIndex += 1 745 746 def formatName(unformatted, z, c, t): 747 # need to turn dims E.g. ('T', 'C', 'Z') into tuple, E.g. (t, c, z) 748 dimMap = {'T': t, 'C':channelMap[c], 'Z': z} 749 dd = tuple([dimMap[d] for d in dims]) 750 return unformatted % dd
751 752 # cecog does this, but other formats may want to start at 0 753 zStart = 1 754 tStart = 1 755 756 # loop through dimensions, saving planes as tiffs. 757 for z in range(sizeZ): 758 for c in range(sizeC): 759 for t in range(sizeT): 760 imageName = formatName(unformattedImageName, z+zStart, c, t+tStart) 761 SU_LOG.debug("downloading plane z: %s c: %s t: %s to %s" % (z, c, t, imageName)) 762 plane = downloadPlane(rawPixelsStore, pixels, z, c, t) 763 i = Image.fromarray(plane) 764 i.save(imageName) 765 766
767 -def createFileFromData(updateService, queryService, filename, data):
768 """ 769 Create a file from the data of type format, setting sha1, .. 770 @param updateService The updateService to create the annotation link. 771 @param filename The name of the file. 772 @param data The data to save. 773 @param format The Format of the file. 774 @return The newly created OriginalFile. 775 """ 776 tempFile = omero.model.OriginalFileI(); 777 tempFile.setName(omero.rtypes.rstring(filename)); 778 tempFile.setPath(omero.rtypes.rstring(filename)); 779 tempFile.setMimetype(omero.rtypes.rstring(CSV_FORMAT)); 780 tempFile.setSize(omero.rtypes.rlong(len(data))); 781 tempFile.setSha1(omero.rtypes.rstring(calcSha1FromData(data))); 782 return updateService.saveAndReturnObject(tempFile);
783
784 -def attachArrayToImage(updateService, image, file, nameSpace):
785 """ 786 Attach an array, stored as a csv file to an image. Returns the annotation. 787 @param updateService The updateService to create the annotation link. 788 @param image The image to attach the data to. 789 @param filename The name of the file. 790 @param namespace The namespace of the file. 791 @return 792 """ 793 fa = omero.model.FileAnnotationI(); 794 fa.setFile(file); 795 fa.setNs(omero.rtypes.rstring(nameSpace)) 796 l = omero.model.ImageAnnotationLinkI(); 797 l.setParent(image); 798 l.setChild(fa); 799 l = updateService.saveAndReturnObject(l); 800 return l.getChild();
801
802 -def uploadArray(rawFileStore, updateService, queryService, image, filename, namespace, array):
803 """ 804 Upload the data to the server, creating the OriginalFile Object and attaching it to the image. 805 @param rawFileStore The rawFileStore used to create the file. 806 @param updateService The updateService to create the annotation link. 807 @param image The image to attach the data to. 808 @param filename The name of the file. 809 @param namespace The name space associated to the annotation. 810 @param data The data to save. 811 @return The newly created file. 812 """ 813 data = arrayToCSV(array); 814 file = createFileFromData(updateService, queryService, filename, data); 815 rawFileStore.setFileId(file.getId().getValue()); 816 fileSize = len(data); 817 increment = 10000; 818 cnt = 0; 819 done = 0 820 while(done!=1): 821 if(increment+cnt<fileSize): 822 blockSize = increment; 823 else: 824 blockSize = fileSize-cnt; 825 done = 1; 826 block = data[cnt:cnt+blockSize]; 827 rawFileStore.write(block, cnt, blockSize); 828 cnt = cnt+blockSize; 829 return attachArrayToImage(updateService, image, file, namespace);
830
831 -def arrayToCSV(data):
832 """ 833 Convert the numpy array data to a csv file. 834 @param data the Numpy Array 835 @return The CSV string. 836 """ 837 size = data.shape; 838 row = size[0]; 839 col = size[1]; 840 strdata =""; 841 for r in range(0,row): 842 for c in range(0, col): 843 strdata = strdata + str(data[r,c]) 844 if(c<col-1): 845 strdata = strdata+','; 846 strdata = strdata + '\n'; 847 return strdata;
848 849
850 -def uploadPlane(rawPixelsStore, plane, z, c, t):
851 """ 852 Upload the plane to the server attching it to the current z,c,t of the already instantiated rawPixelStore. 853 @param rawPixelsStore The rawPixelStore which is already pointing to the data. 854 @param plane The data to upload 855 @param z The Z-Section of the plane. 856 @param c The C-Section of the plane. 857 @param t The T-Section of the plane. 858 """ 859 byteSwappedPlane = plane.byteswap(); 860 convertedPlane = byteSwappedPlane.tostring(); 861 rawPixelsStore.setPlane(convertedPlane, z, c, t)
862 863
864 -def uploadPlaneByRow(rawPixelsStore, plane, z, c, t):
865 """ 866 Upload the plane to the server one row at a time, 867 attching it to the current z,c,t of the already instantiated rawPixelStore. 868 @param rawPixelsStore The rawPixelStore which is already pointing to the data. 869 @param plane The data to upload 870 @param z The Z-Section of the plane. 871 @param c The C-Section of the plane. 872 @param t The T-Section of the plane. 873 """ 874 byteSwappedPlane = plane.byteswap() 875 876 rowCount, colCount = plane.shape 877 for y in range(rowCount): 878 row = byteSwappedPlane[y:y+1, :] # slice y axis into rows 879 convertedRow = row.tostring() 880 rawPixelsStore.setRow(convertedRow, y, z, c, t)
881 882
883 -def getRenderingEngine(session, pixelsId):
884 """ 885 Create the renderingEngine for the pixelsId. 886 @param session The current session to create the renderingEngine from. 887 @return The renderingEngine Service for the pixels. 888 """ 889 renderingEngine = session.createRenderingEngine(); 890 renderingEngine.lookupPixels(pixelsId); 891 if(renderingEngine.lookupRenderingDef(pixelsId)==0): 892 renderingEngine.resetDefaults(); 893 renderingEngine.lookupRenderingDef(pixelsId); 894 renderingEngine.load(); 895 return renderingEngine; 896 897
898 -def createPlaneDef(z,t):
899 """ 900 Create the plane rendering def, for z,t 901 @param Z the Z-Section 902 @param T The T-Point. 903 @return The RenderingDef Object. 904 """ 905 planeDef = omero.romio.PlaneDef() 906 planeDef.t = t; 907 planeDef.z = z; 908 planeDef.x = 0; 909 planeDef.y = 0; 910 planeDef.slice = 0; 911 return planeDef;
912
913 -def getPlaneAsPackedInt(renderingEngine, z, t):
914 """ 915 Get the rendered Image of the plane for the z, t with the default channels. 916 @param renderingEngine The already instantiated renderEngine. 917 @param z The Z-section. 918 @param t The Timepoint. 919 """ 920 planeDef = createPlaneDef(z, t); 921 return renderingEngine.renderAsPackedInt(planeDef);
922
923 -def getRawPixelsStore(session, pixelsId):
924 """ 925 Get the rawPixelsStore for the Image with pixelsId 926 @param pixelsId The pixelsId of the object to retrieve. 927 @return The rawPixelsStore service. 928 """ 929 rawPixelsStore = session.createRawPixelsStore(); 930 rawPixelsStore.setPixelsId(pixelsId); 931 return rawPixelsStore;
932
933 -def getRawFileStore(session, fileId):
934 """ 935 Get the rawFileStore for the file with fileId 936 @param fileId The fileId of the object to retrieve. 937 @return The rawFileStore service. 938 """ 939 rawFileStore = session.createRawFileStore(); 940 rawFileStore.setFileId(fileId); 941 return rawFileStore;
942
943 -def getPlaneInfo(iQuery, pixelsId, asOrderedList = True):
944 """ 945 Get the plane info for the pixels object returning it in order of z,t,c 946 @param iQuery The query service. 947 @param pixelsId The pixels for Id. 948 @param asOrderedList 949 @return list of planeInfoTimes or map["z:t:c:] 950 """ 951 query = "from PlaneInfo as Info where pixels.id='"+str(pixelsId)+"' orderby info.deltaT" 952 infoList = iQuery.findAllByQuery(query,None) 953 954 if(asOrderedList): 955 map = {} 956 for info in infoList: 957 key = "z:"+str(info.theZ.getValue())+"t:"+str(info.theT.getValue())+"c:"+str(info.theC.getValue()); 958 map[key] = info.deltaT.getValue(); 959 return map; 960 else: 961 return infoList;
962
963 -def IdentityFn(commandArgs):
964 return commandArgs;
965 966
967 -def resetRenderingSettings(renderingEngine, pixelsId, cIndex, minValue, maxValue, rgba=None):
968 """ 969 Simply resests the rendering settings for a pixel set, according to the min and max values 970 The rendering engine does NOT have to be primed with pixelsId, as that is handled by this method. 971 972 @param renderingEngine The OMERO rendering engine 973 @param pixelsId The Pixels ID 974 @param minValue Minimum value of rendering window 975 @param maxValue Maximum value of rendering window 976 @param rgba Option to set the colour of the channel. (r,g,b,a) tuple. 977 """ 978 979 renderingEngine.lookupPixels(pixelsId) 980 if not renderingEngine.lookupRenderingDef(pixelsId): 981 renderingEngine.resetDefaults() 982 if rgba == None: 983 rgba=(255,255,255,255) # probably don't want E.g. single channel image to be blue! 984 985 if not renderingEngine.lookupRenderingDef(pixelsId): 986 raise "Still No Rendering Def" 987 988 renderingEngine.load() 989 renderingEngine.setChannelWindow(cIndex, float(minValue), float(maxValue)) 990 if rgba: 991 red, green, blue, alpha = rgba 992 renderingEngine.setRGBA(cIndex, red, green, blue, alpha) 993 renderingEngine.saveCurrentSettings()
994 995
996 -def createNewImage(session, plane2Dlist, imageName, description, dataset=None):
997 """ 998 Creates a new single-channel, single-timepoint image from the list of 2D numpy arrays in plane2Dlist 999 with each numpy 2D plane becoming a Z-section. 1000 1001 @param session An OMERO service factory or equivalent with getQueryService() etc. 1002 @param plane2Dlist A list of numpy 2D arrays, corresponding to Z-planes of new image. 1003 @param imageName Name of new image 1004 @param description Description for the new image 1005 @param dataset If specified, put the image in this dataset. omero.model.Dataset object 1006 1007 @return The new OMERO image: omero.model.ImageI 1008 """ 1009 queryService = session.getQueryService() 1010 pixelsService = session.getPixelsService() 1011 rawPixelStore = session.createRawPixelsStore() 1012 renderingEngine = session.createRenderingEngine() 1013 containerService = session.getContainerService() 1014 1015 pType = plane2Dlist[0].dtype.name 1016 pixelsType = queryService.findByQuery("from PixelsType as p where p.value='%s'" % pType, None) # omero::model::PixelsType 1017 1018 theC, theT = (0,0) 1019 1020 # all planes in plane2Dlist should be same shape. 1021 shape = plane2Dlist[0].shape 1022 sizeY, sizeX = shape 1023 minValue = plane2Dlist[0].min() 1024 maxValue = plane2Dlist[0].max() 1025 1026 # get some other dimensions and create the image. 1027 channelList = [theC] # omero::sys::IntList 1028 sizeZ, sizeT = (len(plane2Dlist),1) 1029 iId = pixelsService.createImage(sizeX, sizeY, sizeZ, sizeT, channelList, pixelsType, imageName, description) 1030 imageId = iId.getValue() 1031 image = containerService.getImages("Image", [imageId], None)[0] 1032 1033 # upload plane data 1034 pixelsId = image.getPrimaryPixels().getId().getValue() 1035 rawPixelStore.setPixelsId(pixelsId, True) 1036 for theZ, plane2D in enumerate(plane2Dlist): 1037 minValue = min(minValue, plane2D.min()) 1038 maxValue = max(maxValue, plane2D.max()) 1039 if plane2D.size > 1000000: 1040 uploadPlaneByRow(rawPixelStore, plane2D, theZ, theC, theT) 1041 else: 1042 uploadPlane(rawPixelStore, plane2D, theZ, theC, theT) 1043 pixelsService.setChannelGlobalMinMax(pixelsId, theC, float(minValue), float(maxValue)) 1044 resetRenderingSettings(renderingEngine, pixelsId, theC, minValue, maxValue) 1045 1046 # put the image in dataset, if specified. 1047 if dataset: 1048 link = omero.model.DatasetImageLinkI() 1049 link.parent = omero.model.DatasetI(dataset.id.val, False) 1050 link.child = omero.model.ImageI(image.id.val, False) 1051 session.getUpdateService().saveObject(link) 1052 1053 renderingEngine.close() 1054 rawPixelStore.close() 1055 return image
1056 1057
1058 -def parseInputs(client, session, processFn=IdentityFn):
1059 """ 1060 parse the inputs from the client object and map it to some other form, values may be transformed by function. 1061 @param client The client object 1062 @param session The current session. 1063 @param processFn A function to transform data to some other form. 1064 @return Parsed inputs as defined by ProcessFn. 1065 """ 1066 inputKeys = client.getInputKeys(); 1067 commandArgs = {}; 1068 for key in inputKeys: 1069 commandArgs[key]=client.getInput(key).getValue(); 1070 return processFn(commandArgs);
1071 1072
1073 -def getROIFromImage(iROIService, imageId, namespace=None):
1074 """ 1075 Get the ROI from the server for the image with the namespace 1076 @param iROIService The iROIService object 1077 @param imageId The imageId to retreive ROI from. 1078 @param namespace The namespace of the ROI. 1079 @return See above. 1080 """ 1081 roiOpts = omero.api.RoiOptions() 1082 if(namespace!=None): 1083 roiOpts.namespace = namespace; 1084 return iROIService.findByImage(imageId, roiOpts);
1085
1086 -def toCSV(list):
1087 """ 1088 Convert a list to a Comma Separated Value string. 1089 @param list The list to convert. 1090 @return See above. 1091 """ 1092 lenList = len(list); 1093 cnt = 0; 1094 str = ""; 1095 for item in list: 1096 str = str + item; 1097 if(cnt < lenList-1): 1098 str = str + ","; 1099 cnt = cnt +1; 1100 return str;
1101
1102 -def toList(csvString):
1103 """ 1104 Convert a csv string to a list of strings 1105 @param csvString The CSV string to convert. 1106 @return See above. 1107 """ 1108 list = csvString.split(','); 1109 for index in range(len(list)): 1110 list[index] = list[index].strip(); 1111 return list;
1112
1113 -def registerNamespace(iQuery, iUpdate, namespace, keywords):
1114 """ 1115 Register a workflow with the server, if the workflow does not exist create it and returns it, 1116 otherwise it returns the already created workflow. 1117 @param iQuery The query service. 1118 @param iUpdate The update service. 1119 @param namespace The namespace of the workflow. 1120 @param keywords The keywords associated with the workflow. 1121 @return see above. 1122 """ 1123 workflow = iQuery.findByQuery("from Namespace as n where n.name = '" + namespace.val+"'", None); 1124 workflowData = WorkflowData(); 1125 if(workflow!=None): 1126 workflowData = WorkflowData(workflow); 1127 else: 1128 workflowData.setNamespace(namespace.val); 1129 splitKeywords = keywords.val.split(','); 1130 1131 SU_LOG.debug(workflowData.asIObject()) 1132 for keyword in splitKeywords: 1133 workflowData.addKeyword(keyword); 1134 SU_LOG.debug(workflowData.asIObject()) 1135 workflow = iUpdate.saveAndReturnObject(workflowData.asIObject()); 1136 return WorkflowData(workflow);
1137
1138 -def findROIByImage(roiService, image, namespace):
1139 """ 1140 Finds the ROI with the given namespace linked to the image. Returns a collection of ROIs. 1141 @param roiService The ROI service. 1142 @param image The image the ROIs are linked to . 1143 @param namespace The namespace of the ROI. 1144 @return see above. 1145 """ 1146 roiOptions = omero.api.RoiOptions(); 1147 roiOptions.namespace = omero.rtypes.rstring(namespace); 1148 results = roiService.findByImage(image, roiOptions); 1149 roiList = []; 1150 for roi in results.rois: 1151 roiList.append(ROIData(roi)); 1152 return roiList;
1153