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

using io.imsave(png_fname, img_as_ubyte(some_binary_mask)) to save compressed mask #294

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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
7 changes: 4 additions & 3 deletions histoqc/AnnotationModule.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
from typing import List, Tuple
from histoqc.BaseImage import printMaskHelper
from skimage import io, img_as_ubyte
from histoqc.SaveModule import saveCompressedMask
import os
from pathlib import PurePosixPath, Path
from shapely.geometry import Polygon
Expand Down Expand Up @@ -108,8 +108,9 @@ def saveAnnotationMask(s, params):
height, width = s["img_mask_use"].shape
annotationMask = annotation_to_mask(width, height, annot_collection, (off_x, off_y), resize_factor) > 0

mask_file_name = f"{s['outdir']}{os.sep}{s['filename']}_annot_{ann_format.lower()}.png"
io.imsave(mask_file_name, img_as_ubyte(annotationMask))
# saving compressed mask
saveCompressedMask(f"{s['outdir']}{os.sep}{s['filename']}_annot_{ann_format.lower()}.png", annotationMask)


prev_mask = s["img_mask_use"]
s["img_mask_use"] = prev_mask & annotationMask
Expand Down
10 changes: 5 additions & 5 deletions histoqc/BasicModule.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import logging
import os
from histoqc.BaseImage import printMaskHelper
from histoqc.SaveModule import saveCompressedMask
from skimage.morphology import remove_small_objects, binary_opening, disk
from skimage import io, color, img_as_ubyte

import matplotlib.pyplot as plt


def getBasicStats(s, params):
Expand Down Expand Up @@ -33,7 +31,8 @@ def finalProcessingSpur(s, params):
mask_opened = binary_opening(mask, selem)
mask_spur = ~mask_opened & mask

io.imsave(s["outdir"] + os.sep + s["filename"] + "_spur.png", img_as_ubyte(mask_spur))
# saving compressed mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_spur.png", mask_spur)

prev_mask = s["img_mask_use"]
s["img_mask_use"] = mask_opened
Expand All @@ -56,7 +55,8 @@ def finalProcessingArea(s, params):
mask_opened = remove_small_objects(mask, min_size=area_thresh)
mask_removed_area = ~mask_opened & mask

io.imsave(s["outdir"] + os.sep + s["filename"] + "_areathresh.png", img_as_ubyte(mask_removed_area))
# saving compressed
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_areathresh.png", mask_removed_area)

prev_mask = s["img_mask_use"]
s["img_mask_use"] = mask_opened > 0
Expand Down
8 changes: 4 additions & 4 deletions histoqc/BlurDetectionModule.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@

import skimage
from histoqc.BaseImage import printMaskHelper
from skimage import io, img_as_ubyte, morphology, measure
from histoqc.SaveModule import saveCompressedMask
from skimage import morphology, measure
from skimage.color import rgb2gray
from skimage.filters import rank
import numpy as np

import matplotlib.pyplot as plt


# Analysis of focus measure operators for shape-from-focus
# Said Pertuza,, Domenec Puiga, Miguel Angel Garciab, 2012
Expand All @@ -31,7 +30,8 @@ def identifyBlurryRegions(s, params):
1] # for some reason resize takes a grayscale and produces a 3chan
mask = s["img_mask_use"] & (mask > 0)

io.imsave(s["outdir"] + os.sep + s["filename"] + "_blurry.png", img_as_ubyte(mask))
# saving compressed mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_blurry.png", mask)
s["img_mask_blurry"] = (mask * 255) > 0

prev_mask = s["img_mask_use"]
Expand Down
30 changes: 7 additions & 23 deletions histoqc/BubbleRegionByRegion.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,17 @@
import logging
import os
import sys

from ast import literal_eval as make_tuple

from distutils.util import strtobool
from histoqc.BaseImage import printMaskHelper
from histoqc.SaveModule import saveCompressedMask

import scipy.signal

from skimage import io, img_as_ubyte
from skimage.filters import gabor_kernel, frangi, gaussian, median, laplace
from skimage.color import rgb2gray
from skimage.morphology import remove_small_objects, disk, binary_opening
from skimage.feature import local_binary_pattern

from skimage.transform import rescale, resize, downscale_local_mean

from math import ceil

from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier

from skimage import io, color
from skimage.morphology import remove_small_objects

from skimage import color

import numpy as np

import matplotlib.pyplot as plt

global_holder = {}

#WARNING: Not as robust as other modules
Expand Down Expand Up @@ -85,7 +68,8 @@ def roiWise(s, params):
#s.addToPrintList(name,
# printMaskHelper(params.get("mask_statistics", s["mask_statistics"]), prev_mask, s["img_mask_use"]))

io.imsave(s["outdir"] + os.sep + s["filename"] + "_BubbleBounds.png", img_as_ubyte(mask)) #.astype(np.uint8) * 255)
# saving compressd mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_BubbleBounds.png", mask) #.astype(np.uint8) * 255)

return

Expand All @@ -108,8 +92,8 @@ def detectSmoothness(s, params):

prev_mask = s["img_mask_use"]
s["img_mask_flat"] = mask_flat

io.imsave(s["outdir"] + os.sep + s["filename"] + "_flat.png", img_as_ubyte(mask_flat & prev_mask))
# saving compressed mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_flat.png", mask_flat & prev_mask)

s["img_mask_use"] = s["img_mask_use"] & ~s["img_mask_flat"]

Expand Down
11 changes: 6 additions & 5 deletions histoqc/ClassificationModule.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
from distutils.util import strtobool

from histoqc.BaseImage import printMaskHelper
from skimage import io, img_as_ubyte, img_as_bool
from histoqc.SaveModule import saveCompressedMask
from skimage import io, img_as_bool
from skimage.filters import gabor_kernel, frangi, gaussian, median, laplace
from skimage.color import rgb2gray
from skimage.morphology import remove_small_objects, disk, dilation
Expand All @@ -21,8 +22,6 @@

import numpy as np

import matplotlib.pyplot as plt


def pixelWise(s, params):
name = params.get("name", "classTask")
Expand Down Expand Up @@ -50,7 +49,8 @@ def pixelWise(s, params):

s.addToPrintList(name, str(mask.mean()))

io.imsave(s["outdir"] + os.sep + s["filename"] + "_" + name + ".png", img_as_ubyte(mask))
# saving compressed mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_" + name + ".png", mask)
s["img_mask_" + name] = (mask * 255) > 0
prev_mask = s["img_mask_use"]
s["img_mask_use"] = s["img_mask_use"] & ~s["img_mask_" + name]
Expand Down Expand Up @@ -227,7 +227,8 @@ def byExampleWithFeatures(s, params):

mask = s["img_mask_use"] & (mask > 0)

io.imsave(s["outdir"] + os.sep + s["filename"] + "_" + name + ".png", img_as_ubyte(mask))
# saving compressed mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_" + name + ".png", mask)
s["img_mask_" + name] = (mask * 255) > 0
prev_mask = s["img_mask_use"]
s["img_mask_use"] = s["img_mask_use"] & ~s["img_mask_" + name]
Expand Down
8 changes: 6 additions & 2 deletions histoqc/DeconvolutionModule.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from skimage.color import gdx_from_rgb, hax_from_rgb, bro_from_rgb, bpx_from_rgb, ahx_from_rgb, \
hpx_from_rgb # need to load all of these in case the user selects them
from distutils.util import strtobool
from histoqc.SaveModule import saveCompressedMask

import matplotlib.pyplot as plt

Expand Down Expand Up @@ -36,7 +37,8 @@ def separateStains(s, params):
for c in range(3):
s.addToPrintList(f"deconv_c{c}_std", str(-100))
s.addToPrintList(f"deconv_c{c}_mean", str(-100))
io.imsave(s["outdir"] + os.sep + s["filename"] + f"_deconv_c{c}.png", img_as_ubyte(np.zeros(mask.shape)))
# saving compressed mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + f"_deconv_c{c}.png", np.zeros(mask.shape))

logging.warning(f"{s['filename']} - DeconvolutionModule.separateStains: NO tissue "
f"remains detectable! Saving Black images")
Expand Down Expand Up @@ -71,6 +73,8 @@ def separateStains(s, params):
s.addToPrintList(f"deconv_c{c}_std", str(dc.std()))

dc = (dc - dc_min) / float(dc_max - dc_min) * mask
io.imsave(s["outdir"] + os.sep + s["filename"] + f"_deconv_c{c}.png", img_as_ubyte(dc))

# saving compressed mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + f"_deconv_c{c}.png", dc)

return
18 changes: 12 additions & 6 deletions histoqc/LightDarkModule.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import os
import numpy as np
from histoqc.BaseImage import printMaskHelper
from skimage import io, color, img_as_ubyte
from histoqc.SaveModule import saveCompressedMask
from skimage import color
from distutils.util import strtobool
from skimage.filters import threshold_otsu, rank
from skimage.morphology import disk
Expand Down Expand Up @@ -34,7 +35,8 @@ def getIntensityThresholdOtsu(s, params):
if strtobool(params.get("invert", "False")):
s["img_mask_" + name] = ~s["img_mask_" + name]

io.imsave(s["outdir"] + os.sep + s["filename"] + "_" + name + ".png", img_as_ubyte(s["img_mask_" + name]))
# saving compressed mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_" + name + ".png", s["img_mask_" + name])

prev_mask = s["img_mask_use"]
s["img_mask_use"] = s["img_mask_use"] & s["img_mask_" + name]
Expand Down Expand Up @@ -84,7 +86,8 @@ def getIntensityThresholdPercent(s, params):
prev_mask = s["img_mask_use"]
s["img_mask_use"] = s["img_mask_use"] & s["img_mask_" + name]

io.imsave(s["outdir"] + os.sep + s["filename"] + "_" + name + ".png", img_as_ubyte(prev_mask & ~s["img_mask_" + name]))
# saving compressed mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_" + name + ".png", prev_mask & ~s["img_mask_" + name])

s.addToPrintList(name,
printMaskHelper(params.get("mask_statistics", s["mask_statistics"]), prev_mask, s["img_mask_use"]))
Expand Down Expand Up @@ -128,7 +131,8 @@ def removeBrightestPixels(s, params):
prev_mask = s["img_mask_use"]
s["img_mask_use"] = s["img_mask_use"] & s["img_mask_bright"]

io.imsave(s["outdir"] + os.sep + s["filename"] + "_bright.png", img_as_ubyte(prev_mask & ~s["img_mask_bright"]))
# saving compressed mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_bright.png", prev_mask & ~s["img_mask_bright"])

s.addToPrintList("brightestPixels",
printMaskHelper(params.get("mask_statistics", s["mask_statistics"]), prev_mask, s["img_mask_use"]))
Expand Down Expand Up @@ -163,7 +167,8 @@ def minimumPixelIntensityNeighborhoodFiltering(s,params):
prev_mask = s["img_mask_use"]
s["img_mask_use"] = s["img_mask_use"] & s["img_mask_bright"]

io.imsave(s["outdir"] + os.sep + s["filename"] + "_bright.png", img_as_ubyte(prev_mask & ~s["img_mask_bright"]))
# saving compressed mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_bright.png", prev_mask & ~s["img_mask_bright"])

s.addToPrintList("brightestPixels",
printMaskHelper(params.get("mask_statistics", s["mask_statistics"]), prev_mask, s["img_mask_use"]))
Expand All @@ -183,6 +188,7 @@ def saveEqualisedImage(s,params):
img = color.rgb2gray(img)

out = exposure.equalize_hist((img*255).astype(np.uint8))
io.imsave(s["outdir"] + os.sep + s["filename"] + "_equalized_thumb.png", img_as_ubyte(out))
# saving compressed mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_equalized_thumb.png", out)

return
13 changes: 8 additions & 5 deletions histoqc/MorphologyModule.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import os
import numpy as np
from histoqc.BaseImage import printMaskHelper
from skimage import io, morphology, img_as_ubyte, measure
from histoqc.SaveModule import saveCompressedMask
from skimage import morphology, measure

from scipy import ndimage as ndi

Expand All @@ -16,7 +17,8 @@ def removeSmallObjects(s, params):
img_reduced = morphology.remove_small_objects(s["img_mask_use"], min_size=min_size)
img_small = np.invert(img_reduced) & s["img_mask_use"]

io.imsave(s["outdir"] + os.sep + s["filename"] + "_small_remove.png", img_as_ubyte(img_small))
# saving commpresed mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_small_remove.png", img_small)
s["img_mask_small_filled"] = (img_small * 255) > 0

prev_mask = s["img_mask_use"]
Expand Down Expand Up @@ -81,7 +83,8 @@ def removeFatlikeTissue(s, params):

mask_fat = mask_dilate & ~mask_dilate_removed

io.imsave(s["outdir"] + os.sep + s["filename"] + "_fatlike.png", img_as_ubyte(mask_fat))
# saving compressed mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_fatlike.png", mask_fat)
s["img_mask_fatlike"] = (mask_fat * 255) > 0

prev_mask = s["img_mask_use"]
Expand Down Expand Up @@ -118,8 +121,8 @@ def fillSmallHoles(s, params):
img_reduced = morphology.remove_small_holes(s["img_mask_use"], area_threshold=min_size)
img_small = img_reduced & np.invert(s["img_mask_use"])


io.imsave(s["outdir"] + os.sep + s["filename"] + "_small_fill.png", img_as_ubyte(img_small))
# saving compressed mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_small_fill.png", img_small)
s["img_mask_small_removed"] = (img_small * 255) > 0

prev_mask = s["img_mask_use"]
Expand Down
23 changes: 15 additions & 8 deletions histoqc/SaveModule.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
from skimage import color
import numpy as np

import matplotlib.pyplot as plt


def blend2Images(img, mask):
if (img.ndim == 3):
Expand All @@ -26,12 +24,13 @@ def saveFinalMask(s, params):
for mask_force in s["img_mask_force"]:
mask[s[mask_force]] = 0

io.imsave(s["outdir"] + os.sep + s["filename"] + "_mask_use.png", img_as_ubyte(mask))
# saving compressed mask
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_mask_use.png", mask)

if strtobool(params.get("use_mask", "True")): # should we create and save the fusion mask?
img = s.getImgThumb(s["image_work_size"])
out = blend2Images(img, mask)
io.imsave(s["outdir"] + os.sep + s["filename"] + "_fuse.png", img_as_ubyte(out))
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_fuse.png" ,out)

return

Expand Down Expand Up @@ -60,7 +59,7 @@ def saveAssociatedImage(s, key:str, dim:int):

associated_img = associated_img.resize(size)
associated_img = np.asarray(associated_img)[:, :, 0:3]
io.imsave(f"{s['outdir']}{os.sep}{s['filename']}_{key}.png", associated_img)
saveCompressedMask(f"{s['outdir']}{os.sep}{s['filename']}_{key}.png" ,associated_img)

def saveMacro(s, params):
dim = params.get("small_dim", 500)
Expand All @@ -78,14 +77,22 @@ def saveMask(s, params):
return

# save mask
io.imsave(f"{s['outdir']}{os.sep}{s['filename']}_{suffix}.png", img_as_ubyte(s["img_mask_use"]))
path = f"{s['outdir']}{os.sep}{s['filename']}_{suffix}.png"
# saving mask with RLE
saveCompressedMask(path, s["img_mask_use"])

def saveThumbnails(s, params):
logging.info(f"{s['filename']} - \tsaveThumbnail")
# we create 2 thumbnails for usage in the front end, one relatively small one, and one larger one
img = s.getImgThumb(params.get("image_work_size", "1.25x"))
io.imsave(s["outdir"] + os.sep + s["filename"] + "_thumb.png", img)
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_thumb.png" ,img)

img = s.getImgThumb(params.get("small_dim", 500))
io.imsave(s["outdir"] + os.sep + s["filename"] + "_thumb_small.png", img)
saveCompressedMask(s["outdir"] + os.sep + s["filename"] + "_thumb.png" ,img)
return

def saveCompressedMask(f_path, img_mask, optimize: bool=True):
# Check if the image is binarized
unique_values = np.unique(img_mask)
bits = 1 if len(unique_values) == 2 else 8
io.imsave(f_path, img_as_ubyte(img_mask),bits=bits, optimize=optimize)