Creating a LibMI project
libmi-init -i slide.svs -o testproj -s 4 -t 256 -g 1024 -c
Get the whole-slide image in the current folder and run the command above. The command would create a new directory named testproj which is the project folder. In this case we use 4 bytes pixel size for pixel-level annotation, 256 x 256 pixels for image tiles and 1024 bytes for grading data tiles. We also copy the image file to the project folder.
Start coding in python
import libmi slide = libmi.Slide('testproj') slide.LoadProject() print((slide.GetWidth(), slide.GetHeight())) slide.SaveProject()
We give the project folder name to specify the project, and use LoadProject function to open this project. Note that each project must be closed before being opened again or the library would raise an exception. After that we get the slide image resolution, and do not forget to close the project finally using SaveProject function.
Writing and reading geometrical annotations
slide.AddAnnoRect((100, 100), (200, 200)) anno = slide.AddAnnoEllipse((300, 300), (100, 200)) anno.SetAnnoColor((255, 0, 0)) print(anno.GetAnnoElliParam()) print(len(slide.GetAnnos()))
We add two annotations to the project, one rectangle and one ellipse. The AddAnno* functions return the annotation object through which we can read or modify the parameters. The GetAnnos function returns all annotations in this project as a list.
Accessing slide properties
for prop in slide.GetPropertyNames(): print('%s : %s' % (prop, slide.GetPropertyValue(prop))) slide.SetPropertyValue('custom_key', 'custom_value') slide.RemoveProperty('custom_key')
Through GetPropertyNames function we can get all property keys as a list. We can use SetPropertyValue to modify property value or create new properties, and use RemoveProperty to remove existing properties.
Reading original image data
slide.SetCurrentRegion((10000, 10000), (10000, 5000)) slide.SetRegionSize((256, 128)) region = slide.ReadRegion() cv2.imwrite('region.png', region)
First, we use SetCurrentRegion to specify the region that we want to read. In this case, we read the image region from (10000, 10000) to (20000, 15000). Next, we use SetRegionSize to set the desired image resolution. In this case, we need an image with (256, 128) resolution as the result. Then ReadRegion will return a numpy array with dimensions [128, 256, 4]. Please note that for numpy the first dimension is the height and the second dimension is the width, which is different from LibMI dimensions.
Writing and reading pixel-level annotations In LibMI, the pixel-level annotation, or segmentation can be regarded as an image with same size as the original image whose pixel data indicate the region that this pixel belongs to. The pixel size of the project determines the upper-limit of number of different regions.
slide.SetCurrentRegion((10000, 10000), (10000, 5000)) slide.SetRegionSize((256, 128)) segm = numpy.empty([128, 256, 4], numpy.uint8) cv2.ellipse(segm, (100, 50), (50, 30), 0, 0, 360, (0, 0, 255, 255), -1) slide.WriteSegm(segm, None)
We use the similar process to specify the region that we need to modify. In this case, we use an ellipse to stimulate a freehand annotation, and red color means region ID 255 x 256 + 255. This is just used to visualize the result, and in actual usage, developers should use uint32 instead to specify the region ID.
slide.SetCurrentRegion((0, 0), (slide.GetWidth(), slide.GetHeight())) slide.SetRegionSize((int(slide.GetWidth() / 100), int(slide.GetHeight() / 100))) overview = slide.ReadSegm() overview.dtype = numpy.uint8 overview = overview.reshape((int(slide.GetHeight() / 100), int(slide.GetWidth() / 100), 4)) print(overview.shape) cv2.imwrite('overview.png', overview)
Then we read the entire pixel-level annotation image as a thumbnail. The ReadSegm function returns a numpy array with dtype = uint32, so we need to transform it to uint8 before outputing the image.
Writing and Reading grading data
slide.SetGrade(100, 3) print(slide.GetGrade(100)) ids = numpy.asarray([500, 1000, 70000, 100000000], numpy.uint32) grades = numpy.asarray([3, 2, 1, 2], numpy.uint8) slide.SetGrades(ids, grades) print(slide.GetGrades(ids))
We can read or write grading data for region IDs once a time through SetGrade and GetGrade, or we can access several of them at once as a second choice. In most situations, the latter method would be more efficient. The upper-limit of region ID depends on the project segmentation pixel size.