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

Colors wrong when saving ND2 to png #52

Open
LordKnish opened this issue Jun 24, 2021 · 9 comments
Open

Colors wrong when saving ND2 to png #52

LordKnish opened this issue Jun 24, 2021 · 9 comments

Comments

@LordKnish
Copy link

Hi,
I am using ND2reader to take each color channel (3 in my case) combine and export to a tif. This is an example of what it should look like:
31 5 21 alk ascending concentration_croppedt01xy01 (1)

but instead I get this image which seems like the colors are completely off.
ImageFromND2_hour0 frame0

doing an image analysis and comparison using ImageMagick it seems like my script is just not saving it as 16 bit or combining as 16 bit at all. Any thoughts?

Image from script -> ImageFromND2_hour0.frame0.png PNG 512x512 512x512+0+0 8-bit sRGB 400303B 0.000u 0:00.002
Image From NisElements -> 31.5.21 alk ascending concentration_croppedt01xy01.tif TIFF 512x512 512x512+0+0 16-bit sRGB 1.51925MiB 0.031u 0:00.035

My script:

import time
start_time = time.time()
from nd2reader import ND2Reader, legacy
import cv2
import numpy as np
import pandas as pd 
import matplotlib.pyplot as plt
import os
# Print iterations progress

filelocation = 'Nd2 Conversion\\31.5.21 ALK ascending concentration_Cropped.nd2'
from nd2reader import ND2Reader
with ND2Reader(filelocation) as images:
    l = len(images) * images[0].metadata['fields_of_view'][-1]
    addition = 100 / l
    np.set_printoptions(precision=3)
    numberoffiles = 0
    for x in range(len(images)):
        for fov in images[x].metadata['fields_of_view']:
            c0 = images.parser.get_image_by_attributes(frame_number=x,field_of_view=fov,channel=0,z_level=0,height=512,width=512)
            c1 = images.parser.get_image_by_attributes(frame_number=x,field_of_view=fov,channel=1,z_level=0,height=512,width=512)
            c2 = images.parser.get_image_by_attributes(frame_number=x,field_of_view=fov,channel=2,z_level=0,height=512,width=512)
            no_img = 3
            imagefinal = c0/no_img + c1/no_img + c2/no_img
            plt.imsave("Nd2 Conversion\\ALK Cropped Python\\ImageFromND2_hour" + str(x) + ".frame" + str(fov) + ".png", imagefinal)
            numberoffiles += 1

print("Complete!")
print("--- %s seconds ---" % (time.time() - start_time))
@LordKnish LordKnish changed the title Colors wrong when saving ND2 to Tif. Colors wrong when saving ND2 to png Jun 24, 2021
@ggirelli
Copy link
Contributor

Hi @LordKnish, I believe the color issue is due to the default value that matplotlib assigns to the cmap option of imsave (your plt.imsave part. The default values is set to use the viridis colormap, while you want an RGB image (see here).

I see different options here:

  1. Change the colormap value to one that suits you best.
  2. Instead of summing the channels, concatenate them to obtain an MxNx3 image and pass it as RGB. imsave should then print it assigning the Red, Green, and Blue colors to the three channels. Just bare in mind that the order here is crucial.

Hope this helps!
Best, G

@LordKnish
Copy link
Author

I tried experimenting with colormaps both through matplotlib and also through cv2 and still had issues with colors not showing up. Also when concatenating the Images together I get an error when trying to save since each array is uin16. When I have tried converting to Uint8 I lose data and get lines in the image.

Also some more info on the channels themselves.
C0 is a gray / white layer that is just the device we are conducting analysis on
C1 is the blue layer (Dapi)
C2 is the red layer (Cy3)

each are two channels and I;16.

Let me know what you think
Thanks, B

@LordKnish
Copy link
Author

@ggirelli This is the results of the colormaps tests I tried. These are the most similar results of colormaps with their respective names. The issue is I am still missing that layer of blue and red from the Cy3 and Dapi layers.

download

@ggirelli
Copy link
Contributor

I see. I have to admit that I have limited experience with cv2 and generally use skimage and tifffileinstead.

Regarding the issue with bit-depth, I would recommend checking out the tifffile package, as I have never had issue in importing/exporting images with it.

Regarding the colormap issue, I have never assigned colors to channels in Python. To the best of my knowledge (quite possibly outdated or simply wrong), the TIFF format has tags for the colorspace and colormap.

I found a post by the curator of the tifffile package with details on how to handle extra ImageJ metadata to specify channel colors, maybe that can help.

@LordKnish
Copy link
Author

LordKnish commented Jun 29, 2021

@ggirelli I am going to try out Tifffile and see how it works with saving a concatenated image.

As for the TIFF formats tags. below is a full analysis of the tiff original image during ImageMagick. Let me know what you think.

  Filename: 31.5.21 alk ascending concentration_croppedt01xy01.tif
  Format: TIFF (Tagged Image File Format)
  Mime type: image/tiff
  Class: DirectClass
  Geometry: 512x512+0+0
  Units: PixelsPerInch
  Colorspace: sRGB
  Type: TrueColor
  Endianness: LSB
  Depth: 16-bit
  Channel depth:
    Red: 16-bit
    Green: 16-bit
    Blue: 16-bit
  Channel statistics:
    Pixels: 262144
    Red:
      min: 0  (0)
      max: 65280 (0.996109)
      mean: 29203.9 (0.445623)
      median: 5120 (0.0781262)
      standard deviation: 11398.8 (0.173935)
      kurtosis: 0.200502
      skewness: 0.0848955
      entropy: 0.93399
    Green:
      min: 0  (0)
      max: 65280 (0.996109)
      mean: 18319.7 (0.27954)
      median: 512 (0.00781262)
      standard deviation: 9184.9 (0.140153)
      kurtosis: 3.60796
      skewness: 1.29658
      entropy: 0.843653
    Blue:
      min: 512  (0.00781262)
      max: 65280 (0.996109)
      mean: 41153.6 (0.627964)
      median: 15104 (0.230472)
      standard deviation: 10664.5 (0.162729)
      kurtosis: 0.205034
      skewness: -0.545971
      entropy: 0.924799
  Image statistics:
    Overall:
      min: 0  (0)
      max: 65280 (0.996109)
      mean: 29559.1 (0.451042)
      median: 6912 (0.10547)
      standard deviation: 10416.1 (0.158939)
      kurtosis: -0.783263
      skewness: 0.191493
      entropy: 0.900814
  Rendering intent: Perceptual
  Gamma: 0.454545
  Chromaticity:
    red primary: (0.64,0.33)
    green primary: (0.3,0.6)
    blue primary: (0.15,0.06)
    white point: (0.3127,0.329)
  Matte color: grey74
  Background color: white
  Border color: srgb(223,223,223)
  Transparent color: none
  Interlace: None
  Intensity: Undefined
  Compose: Over
  Page geometry: 512x512+0+0
  Dispose: Undefined
  Iterations: 0
  Compression: None
  Orientation: TopLeft
  Properties:
    date:create: 2021-06-23T13:33:59+00:00
    date:modify: 2021-06-22T11:13:00+00:00
    signature: da8934404d6a972eef62315c5a993a2a9d7300419660cec52bd535270fcc81cd
    tiff:alpha: unspecified
    tiff:endian: lsb
    tiff:photometric: RGB
    tiff:rows-per-strip: 2
  Artifacts:
    verbose: true
  Tainted: False
  Filesize: 1.51925MiB
  Number pixels: 262144
  Pixels per second: 5.11624MP
  User time: 0.016u
  Elapsed time: 0:01.051
  Version: ImageMagick 7.1.0-1 Q16 x64 2021-06-21 https://imagemagick.org
identify: Unknown field with tag 65325 (0xff2d) encountered. `TIFFReadDirectory' @ warning/tiff.c/TIFFWarnings/960.
identify: Unknown field with tag 65326 (0xff2e) encountered. `TIFFReadDirectory' @ warning/tiff.c/TIFFWarnings/960.
identify: Unknown field with tag 65327 (0xff2f) encountered. `TIFFReadDirectory' @ warning/tiff.c/TIFFWarnings/960.
identify: Unknown field with tag 65329 (0xff31) encountered. `TIFFReadDirectory' @ warning/tiff.c/TIFFWarnings/960.
identify: Unknown field with tag 65330 (0xff32) encountered. `TIFFReadDirectory' @ warning/tiff.c/TIFFWarnings/960.
identify: Unknown field with tag 65331 (0xff33) encountered. `TIFFReadDirectory' @ warning/tiff.c/TIFFWarnings/960.
identify: Unknown field with tag 65332 (0xff34) encountered. `TIFFReadDirectory' @ warning/tiff.c/TIFFWarnings/960.
identify: Unknown field with tag 65333 (0xff35) encountered. `TIFFReadDirectory' @ warning/tiff.c/TIFFWarnings/960.

going to investigate that post from tifffile curator but not sure how well it will work since I want to use the images for analysis from an AI not with ImageJ

@ggirelli
Copy link
Contributor

ggirelli commented Jun 29, 2021

If the analysis is done via deep learning or similar, I would not expect the color label to matter, only the intensity of the different channels (if the ML approach you use can handle them separately). If that is the case, even if you see the wrong colors or use different color maps, would that affect your results? 🤔

@ggirelli
Copy link
Contributor

I would also recommend opening an issue for help in the opencv or tifffile repositories, as they might know more details on this 😄

@LordKnish
Copy link
Author

If the analysis is done via deep learning or similar, I would not expect the color label to matter, only the intensity of the different channels (if the ML approach you use can handle them separately). If that is the case, even if you see the wrong colors or use different color maps, would that affect your results? 🤔

The main thing is that our AI works a bit differently but I can't really go into detail on that. Either way we need to convert the ND2 file to either tiff or png and have the output be the same as NisElements output. First of all I think that combining the channels is the first thing that needs to change. You said concatenating the channels together so I will try that out with Tifffile but just keep in mind that each channel are two channel PIMs frames so I wonder if they need some sort of filter on them? Thoughts?

@LordKnish
Copy link
Author

LordKnish commented Jun 29, 2021

Update @ggirelli I tried out Tifffile and it outputs a black image and posts the following error to the console TiffWriter: data are stored as RGB with contiguous samples. Specify the 'photometric' parameter to silence this warningomplete [ImageFromND2_x0.fov4.png]

I can open an issue there if you are unsure

code:

import time
start_time = time.time()
from nd2reader import ND2Reader, legacy
import cv2
import numpy as np
import pandas as pd 
import matplotlib.pyplot as plt
import os
import tifffile
# Print iterations progress
def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█', printEnd = "\r"):
    """
    Call in a loop to create terminal progress bar
    @params:
        iteration   - Required  : current iteration (Int)
        total       - Required  : total iterations (Int)
        prefix      - Optional  : prefix string (Str)
        suffix      - Optional  : suffix string (Str)
        decimals    - Optional  : positive number of decimals in percent complete (Int)
        length      - Optional  : character length of bar (Int)
        fill        - Optional  : bar fill character (Str)
        printEnd    - Optional  : end character (e.g. "\r", "\r\n") (Str)
    """
    percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
    filledLength = int(length * iteration // total)
    bar = fill * filledLength + '-' * (length - filledLength)
    print(f'\r{prefix} |{bar}| {percent}% {suffix}', end = printEnd)
    # Print New Line on Complete
    if iteration == total: 
        print()

def clearConsole():
    command = 'clear'
    if os.name in ('nt', 'dos'):  # If Machine is running on Windows, use cls
        command = 'cls'
    os.system(command)

filelocation = 'Nd2 Conversion\\31.5.21 ALK ascending concentration_Cropped.nd2'
from nd2reader import ND2Reader
with ND2Reader(filelocation) as images:
    l = len(images) * images[0].metadata['fields_of_view'][-1]
    addition = 100 / l
    np.set_printoptions(precision=3)
    numberoffiles = 0
    for x in range(len(images)):
        for fov in images[x].metadata['fields_of_view']:
            printProgressBar(numberoffiles + addition, l, prefix = 'Progress:', suffix = 'Complete [ImageFromND2_x' + str(x) + ".fov" + str(fov) + ".png]" , length = 100)
            c0 = images.parser.get_image_by_attributes(frame_number=x,field_of_view=fov,channel=0,z_level=0,height=512,width=512)
            c1 = images.parser.get_image_by_attributes(frame_number=x,field_of_view=fov,channel=1,z_level=0,height=512,width=512)
            c2 = images.parser.get_image_by_attributes(frame_number=x,field_of_view=fov,channel=2,z_level=0,height=512,width=512)
            no_img = 3
            #imagefinal = c0/no_img + c1/no_img + c2/no_img
            imagefinal = np.stack((c2,c0,c1),axis=2)
            tifffile.imsave("Nd2 Conversion\\ALK Cropped Python\\ImageFromND2_hour" + str(x) + ".frame" + str(fov) + str(x) + ".tif", imagefinal)
            numberoffiles += 1
            input()
            clearConsole()
clearConsole()
print("Complete!")
print("--- %s seconds ---" % (time.time() - start_time))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants