cortex-lab / Suite2P

Tools for processing 2P recordings
Other
121 stars 66 forks source link

Input TIFF uint16 leads to inverted fluorescence traces #121

Closed generalciao closed 6 years ago

generalciao commented 6 years ago

I first tested Suite2P using the gdrive example, this worked (would be great if you could provide expected results and running time, so users can make sure things wore working). I repeated the exact same analysis, replacing the gdrive TIFF files (5x 200 frames) with a single TIFF containing my own data (1x 1200 frames). The pipeline seemed to run okay, but fluorescence traces for some ROIs are inverted (calcium transients appear as negative deflections). If the registered TIFF is saved and opened in ImageJ, the contrast appears odd. Inspecting the histogram shows that most pixels fall into the range 0 to 32767, but a small fraction is around -32768 and a very small fraction is distributed across the negative side of the spectrum. The most negative pixel values seem to correspond to the strongest signals. The appearance is of an image where the center of bright neurons is black.

So I think what happens is that my source data starts out as a standard 16-bit TIFF (unsigned) with values from 0 to 65535 (uint16). Then during the pipeline, somehow/somewhere the data are rescaled to be represented as signed integers (int16). Pixel values above 32767 seem to wrap around, so 32768 becomes -32768, and e.g. 65535 becomes -1, or similar. It seems this affects not only the registered TIFF (which I understand is optional/convenience), but also the values in FCell. See attached figure. As a result, the spike inference does not work properly either.

Similar and related issues have been noted by others in the past, although the two most relevant issues (#40 and #92) were marked as closed.

From a little research, it seems like 2P systems follow (or create) a variety of conventions of how to store digitized data in TIFF files. A number of systems use non-TIFF binary files as native file storage, and provide export functionality to TIFF. ScanImage seems to use signed 16-bit integers (although this may not always have been the case), and maybe this is why Suite2P uses that convention?

Since Suite2P expects TIFF as input, it would be good to clearly document what assumptions are made about the nature of the data in said TIFF input files. Better would be to support a variety of input formats (including uint16 TIFF, which I think is the "standard" TIFF format, as opposed to int16 TIFF).

roi112-inverted-bug

Thanks for Suite2P!

marius10p commented 6 years ago

Thanks for pointing this out. Scanimage saves as uint16 but only uses 13 bits, so the max value is 8192.

The negative values were necessary due to the fft shifting method (sinc interpolation) sometimes introducing values slightly below 0. I think I will introduce a flag to specify if negative values should be kept, and set it to 0 by default. Clipping the negative values can introduce biases, but only in very low SNR conditions, where the traces will be very noisy anyway.

generalciao commented 6 years ago

Dear Marius, thanks for your reply. I don't see any commits on this yet, so hopefully my delayed response can still be of some help:

Scanimage saves as uint16 but only uses 13 bits, so the max value is 8192.

According to the Vidrio docs, linked here, ScanImage saves signed integers. Further more the values are either 14-bit or 16-bit (so up to +32767), depending on which digitizer is used.

It sounds to me like your data might come from a 14-bit DAQ with a particular offset that avoids negative values? Or perhaps the ScanImage offset calibration is not being applied? Apparently this is stored in the header. Admittedly, the documentation there sounds a bit inconsistent with the TIFF docs linked above, but it's hard to say for sure.

The negative values were necessary due to the fft shifting method (sinc interpolation) sometimes introducing values slightly below 0. I think I will introduce a flag to specify if negative values should be kept, and set it to 0 by default. Clipping the negative values can introduce biases, but only in very low SNR conditions, where the traces will be very noisy anyway.

If I understand correctly, this might indeed help my situation. However, because my data (which is not from ScanImage, and uses the full uint16 range) goes up to 65535, I'm not sure whether it will be compatible with what you describe? Will your sinc interpolation could be able to operate on full-range uint16 data, without causing overflows? Or maybe the overflows don't matter much if they are small?

Thank you!

carsen-stringer commented 6 years ago

Sorry for the delay in addressing this. We have introduced a scaling factor for data that is uint16. The pipeline can detect it (if a pixel is greater than 2^15 then the scaling factor will be set to 2), or you can set it yourself as ops.scaleTiff. Then when writing to the binary file, dreg = int16(dreg / ops.scaleTiff), where dreg are the registered frames (of class 'single'). Let me know if this works for your data, I don't have any uint16 tiffs to test on so there may still be issues

carsen-stringer commented 6 years ago

please reopen this issue, if this is still a problem, thanks

poherron commented 4 years ago

I am also running into issues with my image data being stored as uint16. Won't dividing all your unit16 data by 2 cause you to lose a lot of dynamic range in your luminance? You're cropping off the high values but the low ones aren't extending into negative values by a similar amount with this fix. Maybe I misunderstand how this works. Also, I am trying to save the registered tiffs as uint16 but I get an error that the tiff writing function can't write to uint16: Error using tifflib If SampleFormat is Int, the image datatype is restricted to one of the following: int8, int16, int32.

Error in Tiff/writeAllStrips (line 1969) tifflib('writeEncodedStrip',obj.FileID, stripNum-1,imageData(row_inds,:));

Error in Tiff/write (line 1477) obj.writeAllStrips(varargin{:});

Error in TiffWriter (line 20) t.write(image(:,:,1));

Error in write_reg_to_tiff (line 51) TiffWriter(uint16(data),fname,bitspersamp);

I'm also a little worried if the conversion to single in rigidRegFrames.m has any effect. The span of values in my aligned data (int16) differs from my original data (uint16) and the registered tiffs seem to have a higher background luminance when I open them in ImageJ than the original data. Thanks for any help.

generalciao commented 3 years ago

First, thank you @carsen-stringer for the fix. Before that, I had rescaled my .sbx (scanbox) files using the same strategy you described, with only some success. Unfortunately I didn't get a chance to test your official fix at the time, because by then I had moved on with a different analysis pipeline. In any case, I apologize for not testing your fix and replying to you back then!

The time has come where I'd like to try Suite2P again (initially for the registration pipeline). I understand that all development has moved to the Python version. For my convenience, I'd to do some initial testing with the Matlab version. So I'll hopefully soon know whether your TIFF uint/int fix is working, and I'll report back then.

In the meantime, I wonder: has the registration pipeline seen upgrades in the Python version, i.e. can I expect improved registration if I use the latest Python vs the last Matlab version? In particular, do you currently support 3D alignment (if image planes are tightly spaced, so that any feature can be expected to appear in adjacent planes in the case of z-motion)?

@poherron have you had any luck / made any progress with using this Matlab version to analyze your uint16 TIFF files? What acquisition software is generating them in your case? Thx.

poherron commented 3 years ago

I use a Bruker microscope - their software is PrairieView. I am just using the code but I still do not know how much of a difference the issues I raised are making. I'm basically just hoping if the alignment is changing the dynamic range, it's by an insignificant amount.