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