Open just-meng opened 1 year ago
Hello! I've run into the exact same issue. Do you @just-meng mind explaining to me how to convert the RoiSet.zip to a boolean mask list that's compatible with FISSA? This is what I tried ~
import numpy as np
import tifffile
import roifile
from roifile import ImagejRoi
def roi_to_mask(tiff_path, roi_path):
# get tif dimensions
with tifffile.TiffFile(tiff_path) as tif:
width, height = tif.pages[0].shape
first_image = tif.pages[0].asarray()
maskList = []
roiList = ImagejRoi.fromfile(roi_path)
for roi in roiList:
coordinates = roi.coordinates() # roi boundary coordinates
mask = np.zeros((height, width), dtype=bool) # empty mask
for x, y in coordinates:
mask[int(y), int(x)] = True # fill mask
maskList.append(mask)
return maskList, first_image
masks, img = roi_to_mask(tiff_path, rois_path)
import fissa
experiment = fissa.Experiment([tiff_path],
masks,
verbosity = 6,
nRegions=4)
experiment.separate()
I get TypeError: Wrong ROIs input format: expected a list or sequence, but got a <class 'numpy.ndarray'>
I think all you have to do is to put masks
in a list:
experiment = fissa.Experiment([tiff_path],
[masks],
verbosity = 6,
nRegions=4)
Btw I believe the way you create the mask only returns the boundary of the ROI but not the entire area. Maybe try this:
from skimage.draw import polygon
...
# inside your for loop
mask = np.zeros((height, width), dtype=bool) # empty mask
# instead of this
# for x, y in coordinates:
# mask[int(y), int(x)] = True # fill mask
# do that
rr, cc = polygon(coordinates[:, 1], coordinates[:, 0], shape=(height, width))
mask[rr, cc] = True
maskList.append(mask)
...
You can always visually check the result, e.g. by plt.imshow(mask)
to see if the entire ROI is masked.
Hope this helps! :)
Thank you for the kind explanation @just-meng ! You're right, after sending the code I realized that the only thing I masked was the boundary. I have implemented your solution to fill the entire boundary accordingly.
I have indeed tried inputting the var masks
as a list. Both list and unlisted inputs yield TypeErrors from the same script rois2masks(). Bane of my existence! Thanks again for the quick reply.
That's strange. Can you post the error you get with [masks]
?
Sure! Here's my full script:
import numpy as np
import tifffile
import roifile
from roifile import ImagejRoi
from skimage.draw import polygon
import os
# set dir
path = os.path.expanduser("~" + os.sep + "Desktop")
os.chdir(path)
tiff_path = './GCaMP_AD.tif'
rois_path = './GC_AD_ROI.zip'
def roi_to_mask(tiff_path, roi_path):
# get tif dimensions
with tifffile.TiffFile(tiff_path) as tif:
width, height = tif.pages[0].shape
first_image = tif.pages[0].asarray()
maskList = []
roiList = ImagejRoi.fromfile(roi_path)
n_roi = len(roiList)
for roi in roiList:
coordinates = roi.coordinates() # roi boundary coordinates
mask = np.zeros((height, width), dtype=bool) # empty mask
rr, cc = polygon(coordinates[:, 1], coordinates[:, 0], shape=(height, width))
mask[rr, cc] = True
maskList.append(mask)
return maskList, first_image, n_roi
masks, img, n_roi = roi_to_mask(tiff_path, rois_path)
import fissa
experiment = fissa.Experiment([tiff_path],
[masks],
verbosity = 6,
nRegions=4)
experiment.separate()
Below is the full output:
Adopted default values for 'expansion'
Doing region growing and data extraction for 1 trials...
Images:
./GCaMP_AD.tif
ROI sets:
[array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]]), array([[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
...,
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False],
[False, False, False, ..., False, False, False]])]
nRegions: 4
expansion: 1
[Extraction 1/1] Extraction starting (./GCaMP_AD.tif)
[Extraction 1/1] Loading imagery
[Parallel(n_jobs=-1)]: Using backend ThreadingBackend with 12 concurrent workers.
[Extraction 1/1] Converting ROIs to masks
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_71300\275886425.py in <module>
43 verbosity = 6,
44 nRegions=4)
---> 45 experiment.separate()
~\anaconda3\envs\pWGA\lib\site-packages\fissa\core.py in separate(self, redo_prep, redo_sep)
1362 # Do data preparation
1363 if redo_prep or self.raw is None:
-> 1364 self.separation_prep(redo_prep)
1365 if redo_prep:
1366 redo_sep = True
~\anaconda3\envs\pWGA\lib\site-packages\fissa\core.py in separation_prep(self, redo)
1252 total=n_trial,
1253 desc="Extracting traces",
-> 1254 disable=disable_progressbars,
1255 )
1256 )
~\anaconda3\envs\pWGA\lib\site-packages\joblib\parallel.py in __call__(self, iterable)
1054
1055 with self._backend.retrieval_context():
-> 1056 self.retrieve()
1057 # Make sure that we get a last message telling us we are done
1058 elapsed_time = time.time() - self._start_time
~\anaconda3\envs\pWGA\lib\site-packages\joblib\parallel.py in retrieve(self)
933 try:
934 if getattr(self._backend, 'supports_timeout', False):
--> 935 self._output.extend(job.get(timeout=self.timeout))
936 else:
937 self._output.extend(job.get())
~\anaconda3\envs\pWGA\lib\multiprocessing\pool.py in get(self, timeout)
655 return self._value
656 else:
--> 657 raise self._value
658
659 def _set(self, i, obj):
~\anaconda3\envs\pWGA\lib\multiprocessing\pool.py in worker(inqueue, outqueue, initializer, initargs, maxtasks, wrap_exception)
119 job, i, func, args, kwds = task
120 try:
--> 121 result = (True, func(*args, **kwds))
122 except Exception as e:
123 if wrap_exception and func is not _helper_reraises_exception:
~\anaconda3\envs\pWGA\lib\site-packages\joblib\_parallel_backends.py in __call__(self, *args, **kwargs)
593 def __call__(self, *args, **kwargs):
594 try:
--> 595 return self.func(*args, **kwargs)
596 except KeyboardInterrupt as e:
597 # We capture the KeyboardInterrupt and reraise it as
~\anaconda3\envs\pWGA\lib\site-packages\joblib\parallel.py in __call__(self)
261 with parallel_backend(self._backend, n_jobs=self._n_jobs):
262 return [func(*args, **kwargs)
--> 263 for func, args, kwargs in self.items]
264
265 def __reduce__(self):
~\anaconda3\envs\pWGA\lib\site-packages\joblib\parallel.py in <listcomp>(.0)
261 with parallel_backend(self._backend, n_jobs=self._n_jobs):
262 return [func(*args, **kwargs)
--> 263 for func, args, kwargs in self.items]
264
265 def __reduce__(self):
~\anaconda3\envs\pWGA\lib\site-packages\fissa\core.py in extract(image, rois, nRegions, expansion, datahandler, verbosity, label, total)
207 if verbosity >= 3:
208 print("{}Converting ROIs to masks".format(mheader))
--> 209 base_masks = datahandler.rois2masks(rois, curdata)
210
211 # get the mean image
~\anaconda3\envs\pWGA\lib\site-packages\fissa\extraction.py in rois2masks(cls, rois, data)
122 fissa.roitools.getmasks, fissa.roitools.readrois
123 """
--> 124 return roitools.rois2masks(rois, cls.get_frame_size(data))
125
126 @abc.abstractmethod
~\anaconda3\envs\pWGA\lib\site-packages\fissa\roitools.py in rois2masks(rois, shape)
481 return rois
482
--> 483 raise ValueError("Wrong ROIs input format: unfamiliar shape.")
ValueError: Wrong ROIs input format: unfamiliar shape.
If I simply call masks instead of [masks], I get the error stated previously:
~\anaconda3\envs\pWGA\lib\site-packages\fissa\roitools.py in rois2masks(rois, shape)
471 raise TypeError(
472 "Wrong ROIs input format: expected a list or sequence, but got"
--> 473 " a {}".format(rois.__class__)
474 )
475
TypeError: Wrong ROIs input format: expected a list or sequence, but got a <class 'numpy.ndarray'>
Thus, I tried changing my function in the following way:
maskList.append(mask) --> maskList.append(mask.tolist())
This I think made things better since the error moved a few lines further down lol. It seems like FISSA has an issue with my np boolean masks, so I converted the np arrays to lists. Now it's only worried about the tuples. Again, inputing masks as a list [masks] yields the same TypeError of 'unfamiliar shape'
~\anaconda3\envs\pWGA\lib\site-packages\fissa\roitools.py in rois2masks(rois, shape)
475
476 # If it's a something by 2 array (or vice versa), assume polygons
--> 477 if np.shape(rois[0])[1] == 2 or np.shape(rois[0])[0] == 2:
478 return getmasks(rois, shape)
479 # If it's a list of bigger arrays, assume masks
IndexError: tuple index out of range
I used your code and got no error!
Literally only changed the tiff_path
and rois_path
and the code ran through with no complaints!
The output is too long, but here is the finishing statement:
Finished separating signals from 109 ROIs across 1 trials in 10.6 seconds
Process finished with exit code 0
I am thoroughly defeated then haha. Just to double check -- you ran the code above with [tiff_path] [masks] both listed? I guess I'll just try to reinstall FISSA...perhaps I irreparably messed with some of the internal files while trying to troubleshoot. Wish I could finish separating signals from N rois across 1 trials right now. Thanks again for your help!
*Eh, reinstalling didnt work
Yes with [tiff_path] [masks] both listed just as in your code. If you have a tiff size of 512 x 512 like me, you can try my roiset with your code. If it works, then perhaps the problem is how your export the ROIs from ImageJ. RoiSet.zip
I resized my tif file to 512x512 (it was smaller) and used your RoiSet -- it worked.
I have further news to report. First I thought it worked perhaps because you used polygon ROIs. But I believe you have a number of freehand ones. Then I thought, hey they kept the generic "RoiSet.zip" filename. Well guess what happened after I changed my roi zip filename from GC_AD_ROI.zip to RoiSet.zip? It worked : D
Immense thanks once again for taking the time to get me up and running with this package. Cheers!
Also strange, but I'm glad that your code is now working also for you!
Could you maybe try reading the GC_AD_ROI.zip using a different function?
import roifile
roiList = roifile.roiread(roi_path) # insteadt of roiList = ImagejRoi.fromfile(roi_path)
I tried your version of the roi import and it worked on the roi file named GC_AD_ROI.zip. However, I then re-tried my own version of the roi import on this same zip file and it worked.
What changed? Well here's the order of events: I had the original zip file GC_AD_ROI.zip that I ran my code on got errors which you helped me resolve. After renaming this file to RoiSet I get no errors. Then I open RoiSet in Fiji and save another copy of it as GC_AD_ROI.zip This copy works with both roi import functions ~ roiread & ImagejRoi.fromfile().
I was running all of this on a jupyter notebook. I got everything to work...restarted the kernel...things still work. All I can think of is there was something corrupted with the original file and somehow it got fixed just by renaming it?
It's 5:30am and this feels like a bad fever dream so I'm calling it a day. But thanks once again!
Perhaps you are right with the file being corrupted. Good night!
Hi @just-meng and @EmrickLab, is your issue solved? We are routinely using ROIs from ImageJ without any issue. Happy to help.
I have the same default behavior. The solution suggested in this thread works, but the original issue should be investigated. I used this RoiSet.Zip file, which led to the issue. RoiSet.zip
Hi @nathalierochefort, as @kirolle points out, loading ROIs segmented using ImageJ requires the workaround. I agree that it would be nice to troubleshoot the original issue or incorporate the workaround into the code of FISSA.
Thank you all for the feedback and the suggestion. We will definitely investigate the original issue. Sorry for the delay of the answers: one owner is on paternity leave and members of my lab have used our established pipeline that works well so did not encounter the problem. We will try to solve the issue in January
My ROIs are manual segmented using ImageJ and exported as a RoiSet.zip file. I used this script to run FISSA, and run into the following error. The ROIs seem to cause problems and cannot be converted to masks.
However, when I load the RoiSet.zip and manually convert it into a list of Boolean masks, it works. It is the very same set of ROIs, though.
Is this a bug about specifically dealing with ImageJ .zip files? Can someone fix it?