Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Script for calculating min/max #103

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
259 changes: 259 additions & 0 deletions omero/util_scripts/Min_Max.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
components/tools/OmeroPy/scripts/omero/util_scripts/Min_Max.py

-----------------------------------------------------------------------------
Copyright (C) 2015 University of Dundee. All rights reserved.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

------------------------------------------------------------------------------
"""

from omero.gateway import BlitzGateway
from omero.model import StatsInfoI
from omero.rtypes import rdouble, rlong, rstring
from omero.util.text import TableBuilder
from omero.util.tiles import TileLoop, TileLoopIteration

import omero.scripts as scripts
import omero.util.script_utils as script_utils

from collections import defaultdict
from random import shuffle

from numpy import amin, amax, iinfo
from numpy import average as avg


def calcStatsInfo(conn, imageId, choice, debug=False):
"""
Process a single image here: creating a new StatsInfo object
if necessary.

@param imageId: Original image
"""

oldImage = conn.getObject("Image", imageId)
if oldImage is None:
raise Exception("Image not found for ID:" % imageId)

sizeX = oldImage.getSizeX()
sizeY = oldImage.getSizeY()
sizeZ = oldImage.getSizeZ()
sizeC = oldImage.getSizeC()
sizeT = oldImage.getSizeT()
tileW = min(256, sizeX)
tileH = min(256, sizeY)

zctMap = defaultdict(list)

class Loop(TileLoop):

def createData(self):
return self

def close(self):
pass

only_default = (choice == "default")

class Iteration(TileLoopIteration):

def run(self, data, z, c, t, x, y,
tileWidth, tileHeight, tileCount):

if only_default:
if t != 0 or z != int(sizeZ/2):
return
zctMap[c].append(
(z, c, t, (x, y, tileWidth, tileHeight)))

Loop().forEachTile(
sizeX, sizeY,
sizeZ, sizeC, sizeT,
tileW, tileH, Iteration())

if choice == "random":
for c in zctMap:
copy = list(zctMap[c])
if len(copy) >= 100:
copy = copy[0:100]
shuffle(copy)
zctMap[c] = copy

def channelGen():
byte_count = 0
tile_count = 0
pixels = oldImage.getPrimaryPixels()
rv = dict()
dt = pixels.getTile(0, 0, 0, (0, 0, 16, 16)).dtype
tile_min = iinfo(dt).max # Everything is less
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: this fails for floating point data types.

tile_max = iinfo(dt).min # Everything is more
for c, zctTileList in zctMap.items():
for tileInfo in zctTileList:
tile = pixels.getTile(*tileInfo)
tile_min = min(tile_min, amin(tile))
tile_max = max(tile_max, amax(tile))
byte_count += tile.nbytes
tile_count += 1
rv[c] = (tile_min, tile_max)
yield rv, byte_count, tile_count

statsInfos = dict()
for x, byte_count, tile_count in channelGen():
statsInfos.update(x)

if debug:
print "Loaded %s tile(s) (%s bytes)" % (tile_count, byte_count)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one and other similar print statements error in my hands. Is it because of the python3 environment I am using ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, just use print() like

print("Loaded %s tile(s) (%s bytes)" % (tile_count, byte_count))

return statsInfos


def processImages(conn, scriptParams):
"""
Process the script params to make a list of channel_offsets, then iterate
through the images creating a new image from each with the specified
channel offsets
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be out of date.

"""

message = ""
images, logMessage = script_utils.getObjects(conn, scriptParams)
message += logMessage
if not images:
raise Exception("No images found")
imageIds = sorted(set([i.getId() for i in images]))

choice = scriptParams["Choice"]
debug = bool(scriptParams.get("Debug", False))
globalmin = defaultdict(list)
globalmax = defaultdict(list)

tb = TableBuilder("Context", "Channel", "Min", "Max")
statsInfos = dict()
for iId in imageIds:
statsInfo = calcStatsInfo(conn, iId, choice, debug)
statsInfos[iId] = statsInfo
for c, si in sorted(statsInfo.items()):
c_min, c_max = si
globalmin[c].append(c_min)
globalmax[c].append(c_max)
tb.row("Image:%s" % iId, c, c_min, c_max)

tb.row("", "", "", "")
for c in globalmin:
c_min = globalmin[c]
c_max = globalmax[c]
tb.row("Total: outer ", c, min(c_min), max(c_max))
tb.row("Total: inner ", c, max(c_min), min(c_max))
tb.row("Total: average", c, int(avg(c_min)), int(avg(c_max)))

if scriptParams["DryRun"]:
print str(tb.build())
else:
combine = scriptParams["Combine"]
for iId in imageIds:
img = conn.getObject("Image", iId)
for c, ch in enumerate(img.getChannels(noRE=True)):
si = ch.getStatsInfo()
if si is None:
si = StatsInfoI()
action = "creating"
else:
si = si._obj
action = "updating"

if combine == "no":
si.globalMin = rdouble(statsInfos[iId][c][0])
si.globalMax = rdouble(statsInfos[iId][c][1])
elif combine == "outer":
si.globalMin = rdouble(min(globalmin[c]))
si.globalMax = rdouble(max(globalmax[c]))
elif combine == "inner":
si.globalMin = rdouble(max(globalmin[c]))
si.globalMax = rdouble(min(globalmax[c]))
elif combine == "average":
si.globalMin = rdouble(avg(globalmin[c]))
si.globalMax = rdouble(avg(globalmax[c]))
else:
raise Exception("unknown combine: %s" % combine)

if debug:
print "Image:%s(c=%s) - %s StatsInfo(%s, %s)" % (
iId, c, action, si.globalMin.val, si.globalMax.val)
ch._obj.statsInfo = si
ch.save()

count = sum(map(len, statsInfos.values()))
message += "%s stats info object(s) processed" % count
return message


def runAsScript():
dataTypes = [rstring('Image')]
client = scripts.client(
'MinMax.py',
"""Create or reset StatsInfo objects for all channels

See http://help.openmicroscopy.org/utility-scripts.html""",

scripts.String(
"Data_Type", optional=False, grouping="1",
description="Pick Images by 'Image' ID or by the ID of their "
"Dataset'", values=dataTypes, default="Image"),

scripts.List(
"IDs", optional=False, grouping="2",
description="List of Dataset IDs or Image IDs to "
"process.").ofType(rlong(0)),

scripts.Bool(
"DryRun", optional=True, grouping="3",
description="Whether to print or set values",
default=True),

scripts.String(
"Choice", optional=True, grouping="4",
description="How to choose which planes will be chosen",
default="default",
values=("default", "random", "all")),

scripts.String(
"Combine", optional=True, grouping="5",
description="Whether and if so how to combine values",
default="no",
values=("no", "outer", "inner", "average")),

scripts.Bool(
"Debug", optional=True, grouping="6",
description="Whether to print debug statements",
default=False),

version="5.1.3",
authors=["Josh Moore", "OME Team"],
institutions=["University of Dundee"],
contact="[email protected]",
)

try:
scriptParams = client.getInputs(unwrap=True)
conn = BlitzGateway(client_obj=client)
message = processImages(conn, scriptParams)
client.setOutput("Message", rstring(message))

finally:
client.closeSession()

if __name__ == "__main__":
runAsScript()