Skip to content

Commit

Permalink
pytest fcns added, testmode paths added to open fcn, init shape contr…
Browse files Browse the repository at this point in the history
…ols, initroi fcn list append fixed, init file list fcn sanity check
  • Loading branch information
spreka committed Nov 6, 2023
1 parent c617b79 commit d133b88
Show file tree
Hide file tree
Showing 15 changed files with 1,021 additions and 21 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,6 @@ demo/img_ROIs_classes.zip
masks
src/napari_annotatorj/models/*
src/napari_annotatorj/unet/__pycache__/
src/napari_annotatorj/default_models/*
src/napari_annotatorj/default_models/*
src/napari_annotatorj/pyinstaller/
src/napari_annotatorj/build/
11 changes: 10 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,13 @@ requires = ["setuptools", "wheel", "setuptools_scm"]
build-backend = "setuptools.build_meta"

[tool.setuptools_scm]
write_to = "src/napari_annotatorj/_version.py"
write_to = "src/napari_annotatorj/_version.py"

[tool.pytest.ini_options]
filterwarnings = [
"error",
"ignore::DeprecationWarning",
# note the use of single quote below to denote "raw" strings in TOML
'ignore:function ham\(\) is deprecated:DeprecationWarning',
"ignore::FutureWarning",
]
56 changes: 45 additions & 11 deletions src/napari_annotatorj/_dock_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def __init__(self, napari_viewer):
self.curPredictionImage=None
self.curPredictionImageName=None
self.curOrigImage=None
self.allowContAssistBbox=True
self.allowContAssistBbox=False #True
# '0' is the default GPU if any, otherwise fall back to cpu
# valid values are: ['cpu','0','1','2',...]
self.gpuSetting='cpu'
Expand Down Expand Up @@ -461,6 +461,8 @@ def openNew(self):
if os.path.exists(self.test_image):
img=skimage.io.imread(self.test_image)
print('Test image read successfully')
self.defDir=os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))),'demo/')
self.defFile='img.png'
else:
print('Test image could not be found')
else:
Expand Down Expand Up @@ -837,6 +839,8 @@ def finishOpenNewInit(self,initSrc=None):
roiLayer.mode='add_polygon'
if self.freeHandROIvis not in roiLayer.mouse_drag_callbacks:
roiLayer.mouse_drag_callbacks.append(self.freeHandROIvis)

self.initShapeControls()

# chkbx setting moved to its own fcn initChkBoxes

Expand Down Expand Up @@ -881,6 +885,8 @@ def finishOpenNewInit(self,initSrc=None):
if self.freeHandROIvis in roiLayer.mouse_drag_callbacks:
roiLayer.mouse_drag_callbacks.remove(self.freeHandROIvis)

self.initShapeControls()

# chkbx setting moved to its own fcn initChkBoxes


Expand Down Expand Up @@ -1083,6 +1089,7 @@ def loadROIs(self):
self.bindKeys(roiLayer)


'''
def loadROIs2(self):
# temporarily load a test ImageJ ROI.zip file with contours created in ImageJ and saved with AnnotatorJ
# later this will start a browser dialog to select the annotation file
Expand Down Expand Up @@ -1117,6 +1124,7 @@ def loadROIs2(self):
#shapesLayer.mode = 'select'
# select the "add polygon" mode from the controls by default to enable freehand ROI drawing
shapesLayer.mode = 'add_polygon'
'''

def initRoiManager(self):
# the rois will be stored in this object as in ImageJ's RoiManager
Expand Down Expand Up @@ -1397,7 +1405,10 @@ def importROIsFromMaskImage(self,mask,layerName='ROI'):
roiLayer=self.findROIlayer(layerName=layerName)
if roiLayer is not None:
roiLayer.add_polygons(shapes,edge_width=self.annotEdgeWidth,edge_color=roiColours,face_color=[0,0,0,0])
roiLayer.properties=roiProps
#roiLayer.properties=roiProps
numpy.append(roiLayer.properties['class'],numpy.array(roiProps['class']))
numpy.append(roiLayer.properties['name'],roiProps['name'])
numpy.append(roiLayer.properties['nameInt'],numpy.array(roiProps['nameInt']))

else:
print(f'Cannot find the ROI layer')
Expand Down Expand Up @@ -3585,12 +3596,7 @@ def updateControls(self,layerName):
from napari._qt.layer_controls.qt_shapes_controls import QtShapesControls

#shapeControls=None
if self.shapeControls is None:
for c in self.viewer.window._qt_viewer.controls.children():
if isinstance(c,QtShapesControls) and c.layer.name==layerName:
self.shapeControls=c
self.shapeControls.widthSlider.valueChanged.connect(self.updateEdgeWidths)
break
self.initShapeControls(layerName=layerName)
if self.shapeControls is None:
print('Could not find the shapeControls')
return
Expand All @@ -3599,6 +3605,31 @@ def updateControls(self,layerName):
self.shapeControls.widthSlider.setValue(self.annotEdgeWidth)


def initShapeControls(self,layerName='ROI',reinit=False):
from napari._qt.layer_controls.qt_shapes_controls import QtShapesControls
#if self.shapeControls is None or reinit:
if self.shapeControls is not None:
# check if valid
try:
self.shapeControls.widthSlider.name()
self.doInitShapeControls(layerName)
except Exception as e:
# does not exist
self.doInitShapeControls(layerName)
else:
self.doInitShapeControls(layerName)


def doInitShapeControls(self,layerName='ROI'):
from napari._qt.layer_controls.qt_shapes_controls import QtShapesControls
for c in self.viewer.window._qt_viewer.controls.children():
if isinstance(c,QtShapesControls) and c.layer.name==layerName:
self.shapeControls=c
self.shapeControls.widthSlider.valueChanged.connect(self.updateEdgeWidths)
print(f'---- reinited shape controls to layer {layerName}')
break


def updateEdgeWidths(self,value):
roiLayer=self.findROIlayer()
for i in range(roiLayer.nshapes):
Expand Down Expand Up @@ -8587,6 +8618,7 @@ def setAnnotType(self):
if self.annotatorjObj.freeHandROIvis not in roiLayer.mouse_drag_callbacks:
roiLayer.mouse_drag_callbacks.append(self.annotatorjObj.freeHandROIvis)
self.annotatorjObj.viewer.layers.selection.add(roiLayer)
self.annotatorjObj.initShapeControls(reinit=True)
elif newAnnotType=='bbox':
roiLayer=self.annotatorjObj.findROIlayer()
if roiLayer is None:
Expand All @@ -8596,6 +8628,7 @@ def setAnnotType(self):
if self.annotatorjObj.freeHandROIvis in roiLayer.mouse_drag_callbacks:
roiLayer.mouse_drag_callbacks.remove(self.annotatorjObj.freeHandROIvis)
self.annotatorjObj.viewer.layers.selection.add(roiLayer)
self.annotatorjObj.initShapeControls(reinit=True)
elif newAnnotType=='semantic':
labelLayer=self.annotatorjObj.findLabelsLayerName(layerName='semantic')
if labelLayer is None:
Expand Down Expand Up @@ -10472,10 +10505,11 @@ def initFileList(annotatorjObj,callback):
fileList=QListWidget()
fileList.setSelectionMode(QAbstractItemView.SingleSelection)

for fi,f in enumerate(annotatorjObj.curFileList):
fileList.insertItem(fi,f)
if annotatorjObj.curFileList is not None:
for fi,f in enumerate(annotatorjObj.curFileList):
fileList.insertItem(fi,f)

fileList.setCurrentItem(fileList.item(annotatorjObj.curFileIdx))
fileList.setCurrentItem(fileList.item(annotatorjObj.curFileIdx))

fileList.currentItemChanged.connect(callback)

Expand Down
38 changes: 38 additions & 0 deletions src/napari_annotatorj/_tests/mimic_roiloading_frommask.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import napari
from _dock_widget import AnnotatorJ
from roifile import ImagejRoi
from napari.layers import Shapes, Image, Labels, Layer

def countLayers(layers,layerType=Image):
c=0
for x in layers:
if (x.__class__ is layerType):
c+=1
return c

viewer = napari.Viewer()
pluginInstance=AnnotatorJ(viewer)
viewer.window.add_dock_widget(pluginInstance,name='AnnotatorJ')

tmp_path="C:/work/szbk/annotatorj/testing_napari/dummying_nucleus/masks_demo/labelled_masks/"
pluginInstance.defFile='full adj.tiff'
# load dummy roi
rois=ImagejRoi.fromfile(pluginInstance.test_rois)
shapesLayer=pluginInstance.extractROIdata(rois)
n=len(shapesLayer.data)
print(f'numshapes: {n}')
# add 2nd shapes layer with these rois
pluginInstance.viewer.add_layer(shapesLayer)
prev_count_shapes=countLayers(pluginInstance.viewer.layers,layerType=Shapes)
print(f'before: {prev_count_shapes}')
#'''
pluginInstance.viewer.layers.remove('ROI')
print(f'is 2?: {countLayers(pluginInstance.viewer.layers,layerType=Shapes)}')
pluginInstance.loadRoisFromMask(tmp_path,False)
after_count_shapes=countLayers(pluginInstance.viewer.layers,layerType=Shapes)
print(f'after: {after_count_shapes}')
newShapesLayer=pluginInstance.viewer.layers[-1]
print(f'new shapes num: {len(newShapesLayer.data)}')
#'''

napari.run()
84 changes: 84 additions & 0 deletions src/napari_annotatorj/_tests/mimic_roiloading_fromtext.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import napari
from _dock_widget import AnnotatorJ,ExportFrame
from roifile import ImagejRoi
from napari.layers import Shapes, Image, Labels, Layer
import os,sys

def countLayers(layers,layerType=Image):
c=0
for x in layers:
if (x.__class__ is layerType):
c+=1
return c

viewer = napari.Viewer()
pluginInstance=AnnotatorJ(viewer)
viewer.window.add_dock_widget(pluginInstance,name='AnnotatorJ')

tmp_path="C:/work/szbk/annotatorj/testing_napari/dummying_nucleus/coording/"
pluginInstance.defFile='dummy_mask.tiff'
filename='dummy_mask.csv'
filename2='dummy_mask.txt'
# load dummy roi
rois=ImagejRoi.fromfile(pluginInstance.test_rois)
shapesLayer=pluginInstance.extractROIdata(rois)
n=len(shapesLayer.data)
print(f'numshapes: {n}')
prev_count_shapes=countLayers(pluginInstance.viewer.layers,layerType=Shapes)
print(f'before: {prev_count_shapes}')

if os.path.isfile(os.path.join(tmp_path,filename)):
os.remove(os.path.join(tmp_path,filename))
if os.path.isfile(os.path.join(tmp_path,filename2)):
os.remove(os.path.join(tmp_path,filename2))

pluginInstance.ExportFrame=ExportFrame(pluginInstance.viewer,annotatorjObj=pluginInstance)
bboxes=pluginInstance.ExportFrame.fillBboxList(shapesLayer,len(shapesLayer.data))
pluginInstance.ExportFrame.saveExportedCSV(bboxes,os.path.join(tmp_path,filename))
success=os.path.isfile(os.path.join(tmp_path,filename))
print(f'wrote file: {success}')

pluginInstance.loadRoisFromCoords(tmp_path)
print(f'loaded: {countLayers(pluginInstance.viewer.layers,layerType=Shapes)}')
#'''
after_count_shapes=countLayers(pluginInstance.viewer.layers,layerType=Shapes)
print(f'after: {after_count_shapes}')
newShapesLayer=pluginInstance.viewer.layers[-1]
print(f'new shapes num: {len(newShapesLayer.data)}')
#'''

# remove it
print(f'layers before REMOVE: {pluginInstance.viewer.layers}')
pluginInstance.viewer.layers.remove('ROI')
print(f'--------------- REMOVING ROI LAYER -----------------')
print(f'after remove layer count: {countLayers(pluginInstance.viewer.layers,layerType=Shapes)}')
print(f'layers after REMOVE: {pluginInstance.viewer.layers}')
os.remove(os.path.join(tmp_path,filename))

# write yolo file
bboxes=pluginInstance.ExportFrame.fillBboxListYOLO(shapesLayer,n,256,256)
pluginInstance.ExportFrame.saveExportedCSVyolo(bboxes,os.path.join(tmp_path,filename2))
success=os.path.isfile(os.path.join(tmp_path,filename2))
print(f'wrote second file: {success}')

pluginInstance.loadRoisFromCoords(tmp_path)
print(f'loaded 2nd: {countLayers(pluginInstance.viewer.layers,layerType=Shapes)}')
newShapesLayer=pluginInstance.viewer.layers[-1]
print(f'numshapes 2nd: {len(newShapesLayer.data)}')

pluginInstance.testMode=True
pluginInstance.openNew()
print(f'opened image')
pluginInstance.testMode=False
pluginInstance.defFile='dummy_mask.tiff'
pluginInstance.loadRoisFromCoords(tmp_path)
print(f'loaded 3rd: {countLayers(pluginInstance.viewer.layers,layerType=Shapes)}')
newShapesLayer=pluginInstance.viewer.layers[-1]
print(f'numshapes 3rd: {len(newShapesLayer.data)}')


napari.run()




Loading

0 comments on commit d133b88

Please sign in to comment.