Example #1
0
    def testGridFSAssetstore(self):
        from girder.plugins.large_image.models.image_item import ImageItem

        file = self._uploadFile(
            os.path.join(os.environ['LARGE_IMAGE_DATA'], 'sample_image.ptif'))
        itemId = str(file['itemId'])
        item = Item().load(itemId, user=self.admin)
        # We should be able to read the metadata
        source = ImageItem().tileSource(item)
        metadata = source.getMetadata()
        self.assertEqual(metadata['sizeX'], 58368)
        self.assertEqual(metadata['sizeY'], 12288)
        self.assertEqual(metadata['levels'], 9)
Example #2
0
    def testGetSingleTile(self):
        from girder.plugins.large_image.models.image_item import ImageItem

        file = self._uploadFile(
            os.path.join(os.environ['LARGE_IMAGE_DATA'], 'sample_image.ptif'))
        itemId = str(file['itemId'])
        item = Item().load(itemId, user=self.admin)
        source = ImageItem().tileSource(item)

        sourceRegion = {
            'width': 0.7,
            'height': 0.6,
            'left': 0.15,
            'top': 0.2,
            'units': 'fraction'
        }
        sourceScale = {'magnification': 5}
        targetScale = {'magnification': 2.5}
        tile = source.getSingleTile(region=sourceRegion,
                                    scale=sourceScale,
                                    tile_position=25)
        self.assertEqual(tile['tile_position']['position'], 25)
        self.assertEqual(tile['tile_position']['level_x'], 8)
        self.assertEqual(tile['tile_position']['level_y'], 2)
        self.assertEqual(tile['tile_position']['region_x'], 4)
        self.assertEqual(tile['tile_position']['region_y'], 1)
        self.assertEqual(tile['iterator_range']['level_x_min'], 4)
        self.assertEqual(tile['iterator_range']['level_y_min'], 1)
        self.assertEqual(tile['iterator_range']['level_x_max'], 25)
        self.assertEqual(tile['iterator_range']['level_y_max'], 5)
        self.assertEqual(tile['iterator_range']['region_x_max'], 21)
        self.assertEqual(tile['iterator_range']['region_y_max'], 4)
        self.assertEqual(tile['iterator_range']['position'], 84)

        tile = source.getSingleTileAtAnotherScale(sourceRegion,
                                                  sourceScale,
                                                  targetScale,
                                                  tile_position=25)
        self.assertEqual(tile['tile_position']['position'], 25)
        self.assertEqual(tile['tile_position']['level_x'], 5)
        self.assertEqual(tile['tile_position']['level_y'], 2)
        self.assertEqual(tile['tile_position']['region_x'], 3)
        self.assertEqual(tile['tile_position']['region_y'], 2)
        self.assertEqual(tile['iterator_range']['level_x_min'], 2)
        self.assertEqual(tile['iterator_range']['level_y_min'], 0)
        self.assertEqual(tile['iterator_range']['level_x_max'], 13)
        self.assertEqual(tile['iterator_range']['level_y_max'], 3)
        self.assertEqual(tile['iterator_range']['region_x_max'], 11)
        self.assertEqual(tile['iterator_range']['region_y_max'], 3)
        self.assertEqual(tile['iterator_range']['position'], 33)
Example #3
0
 def _getBound(self, item):
     minervaMeta = item['meta']['minerva']
     if 'dataset_type' not in minervaMeta:
         return
     if (minervaMeta['dataset_type'] == 'geojson' or
             minervaMeta['dataset_type'] == 'geojson-timeseries'):
         geometry = None
         if minervaMeta['dataset_type'] == 'geojson':
             geometry = self.downloadDataset(item)
         if minervaMeta['dataset_type'] == 'geojson-timeseries':
             geometries = self.downloadDataset(item)
             geometry = geometries[0]['geojson']
         geometry = unwrapFeature(geometry)
         geom = shape(geometry)
         return {
             'lrx': geom.bounds[2],
             'lry': geom.bounds[1],
             'ulx': geom.bounds[0],
             'uly': geom.bounds[3]
         }
     elif minervaMeta['dataset_type'] == 'geotiff':
         info = ImageItem().tileSource(item).getMetadata()
         bounds = info['bounds']
         return {
             'lrx': bounds['xmax'],
             'lry': bounds['ymin'],
             'ulx': bounds['xmin'],
             'uly': bounds['ymax']
         }
Example #4
0
    def testFilesystemAssetstore(self):
        from girder.plugins.large_image.models.image_item import ImageItem
        from girder.plugins.large_image.cache_util import cachesClear

        file = self._uploadFile(
            os.path.join(os.environ['LARGE_IMAGE_DATA'], 'sample_image.ptif'))
        itemId = str(file['itemId'])
        item = Item().load(itemId, user=self.admin)
        file = File().load(item['largeImage']['fileId'], force=True)
        # With a second file, large image would prefer to use the Girder mount,
        # if available
        File().createLinkFile('second', item, 'item', 'http://nourl.com',
                              self.admin)
        cachesClear()
        source = ImageItem().tileSource(item)
        # The file path should just be the local path
        self.assertEqual(source._getLargeImagePath(),
                         File().getLocalFilePath(file))
Example #5
0
    def thumbnail(self, image, params):
        width = int(params.get('width', 256))
        height = int(params.get('height', 256))
        thumbData, thumbMime = ImageItem().getThumbnail(image, width=width, height=height)

        # Only setRawResponse now, as this handler may return a JSON error
        # earlier
        setRawResponse()
        setResponseHeader('Content-Type', thumbMime)
        return thumbData
Example #6
0
    def _generateLargeimage(self, image, originalFile):
        user = User().load(image['creatorId'], force=True, exc=True)
        # Use admin user, to ensure that worker always has access
        token = Token().createToken(
            user=getAdminUser(),
            days=1,
            scope=[TokenScope.DATA_READ, TokenScope.DATA_WRITE])

        job = ImageItem().createImageItem(image, originalFile, user, token)
        return job
Example #7
0
    def testGridFSAssetstore(self):
        from girder.plugins.large_image.models.image_item import ImageItem
        from girder.plugins.large_image.tilesource import TileSourceException

        file = self._uploadFile(
            os.path.join(os.environ['LARGE_IMAGE_DATA'], 'sample_image.ptif'))
        itemId = str(file['itemId'])
        item = Item().load(itemId, user=self.admin)
        # We should get an error that this isn't a large image
        with six.assertRaisesRegex(self, TileSourceException,
                                   'No large image file in this item'):
            ImageItem().tileSource(item)
Example #8
0
 def getTile(self, image, z, x, y, params):
     try:
         x, y, z = int(x), int(y), int(z)
     except ValueError:
         raise RestException('x, y, and z must be integers')
     if x < 0 or y < 0 or z < 0:
         raise RestException('x, y, and z must be positive integers')
     try:
         tileData, tileMime = ImageItem().getTile(image, x, y, z)
     except TileGeneralException as e:
         raise RestException(e.message, code=404)
     setResponseHeader('Content-Type', tileMime)
     setRawResponse()
     return tileData
Example #9
0
    def testGetPixel(self):
        from girder.plugins.large_image.models.image_item import ImageItem

        file = self._uploadFile(
            os.path.join(
                os.environ['LARGE_IMAGE_DATA'],
                'sample_jp2k_33003_TCGA-CV-7242-'
                '11A-01-TS1.1838afb1-9eee-4a70-9ae3-50e3ab45e242.svs'))
        itemId = str(file['itemId'])
        item = Item().load(itemId, user=self.admin)
        source = ImageItem().tileSource(item)

        pixel = source.getPixel(region={'left': 12125, 'top': 10640})
        self.assertEqual(pixel, {'r': 156, 'g': 98, 'b': 138, 'a': 255})

        pixel = source.getPixel(region={
            'left': 3.0555,
            'top': 2.68128,
            'units': 'mm'
        })
        self.assertEqual(pixel, {'r': 156, 'g': 98, 'b': 138, 'a': 255})

        pixel = source.getPixel(region={
            'top': 10640,
            'right': 12126,
            'bottom': 12000
        })
        self.assertEqual(pixel, {'r': 156, 'g': 98, 'b': 138, 'a': 255})

        pixel = source.getPixel(region={
            'left': 12125,
            'top': 10640,
            'right': 13000
        })
        self.assertEqual(pixel, {'r': 156, 'g': 98, 'b': 138, 'a': 255})

        pixel = source.getPixel(region={
            'left': 12125,
            'top': 10640
        },
                                includeTileRecord=True)
        self.assertIn('tile', pixel)
Example #10
0
    def testGetRegion(self):
        from girder.plugins.large_image import tilesource
        from girder.plugins.large_image.models.image_item import ImageItem

        file = self._uploadFile(
            os.path.join(
                os.environ['LARGE_IMAGE_DATA'],
                'sample_jp2k_33003_TCGA-CV-7242-'
                '11A-01-TS1.1838afb1-9eee-4a70-9ae3-50e3ab45e242.svs'))
        itemId = str(file['itemId'])
        item = Item().load(itemId, user=self.admin)
        source = ImageItem().tileSource(item)

        # By default, getRegion gets an image
        image, mimeType = source.getRegion(scale={'magnification': 2.5})
        self.assertEqual(mimeType, 'image/jpeg')
        self.assertEqual(image[:len(common.JPEGHeader)], common.JPEGHeader)

        # Adding a tile position request should be ignored
        image2, imageFormat = source.getRegion(scale={'magnification': 2.5},
                                               tile_position=1)
        self.assertEqual(image, image2)

        # We should be able to get a NUMPY array instead
        image, imageFormat = source.getRegion(
            scale={'magnification': 2.5}, format=tilesource.TILE_FORMAT_NUMPY)
        self.assertEqual(imageFormat, tilesource.TILE_FORMAT_NUMPY)
        self.assertTrue(isinstance(image, numpy.ndarray))
        self.assertEqual(image.shape, (1447, 1438, 4))

        # We should be able to get a PIL image
        image, imageFormat = source.getRegion(
            scale={'magnification': 2.5},
            format=(tilesource.TILE_FORMAT_PIL, tilesource.TILE_FORMAT_NUMPY))
        self.assertEqual(imageFormat, tilesource.TILE_FORMAT_PIL)
        self.assertEqual(image.width, 1438)
        self.assertEqual(image.height, 1447)
Example #11
0
    def testConvertRegionScale(self):
        from girder.plugins.large_image import tilesource
        from girder.plugins.large_image.models.image_item import ImageItem

        file = self._uploadFile(
            os.path.join(
                os.environ['LARGE_IMAGE_DATA'],
                'sample_jp2k_33003_TCGA-CV-7242-'
                '11A-01-TS1.1838afb1-9eee-4a70-9ae3-50e3ab45e242.svs'))
        itemId = str(file['itemId'])
        item = Item().load(itemId, user=self.admin)
        source = ImageItem().tileSource(item)

        # If we aren't using pixels as our units and don't specify a target
        # unit, this should do nothing.  This source image is 23021 x 23162
        sourceRegion = {'width': 0.8, 'height': 0.7, 'units': 'fraction'}
        targetRegion = source.convertRegionScale(sourceRegion)
        self.assertEqual(sourceRegion, targetRegion)

        # Units must be valid
        with six.assertRaisesRegex(self, ValueError, 'Invalid units'):
            source.convertRegionScale({'units': 'unknown'})
        with six.assertRaisesRegex(self, ValueError, 'Invalid units'):
            source.convertRegionScale(sourceRegion, targetUnits='unknown')

        # We can convert to pixels
        targetRegion = source.convertRegionScale(
            sourceRegion,
            targetScale={'magnification': 2.5},
            targetUnits='pixels')
        self.assertEqual(int(targetRegion['width']), 1151)
        self.assertEqual(int(targetRegion['height']), 1013)
        self.assertEqual(targetRegion['units'], 'mag_pixels')

        # Now use that to convert to a different magnification
        sourceRegion = targetRegion
        sourceScale = {'magnification': 2.5}

        # Test other conversions
        targetScale = {'magnification': 1.25}
        targetRegion = source.convertRegionScale(sourceRegion, sourceScale,
                                                 targetScale)
        self.assertEqual(int(targetRegion['width']), 18417)
        self.assertEqual(int(targetRegion['height']), 16213)
        self.assertEqual(targetRegion['units'], 'base_pixels')

        targetRegion = source.convertRegionScale(sourceRegion,
                                                 sourceScale,
                                                 targetScale,
                                                 targetUnits='fraction')
        self.assertAlmostEqual(targetRegion['width'], 0.8, places=4)
        self.assertAlmostEqual(targetRegion['height'], 0.7, places=4)
        self.assertEqual(targetRegion['units'], 'fraction')

        targetRegion = source.convertRegionScale(sourceRegion,
                                                 sourceScale,
                                                 targetScale,
                                                 targetUnits='mm')
        self.assertAlmostEqual(targetRegion['width'], 4.6411, places=3)
        self.assertAlmostEqual(targetRegion['height'], 4.0857, places=3)
        self.assertEqual(targetRegion['units'], 'mm')

        targetRegion = source.convertRegionScale(sourceRegion,
                                                 sourceScale,
                                                 None,
                                                 targetUnits='mm')
        self.assertAlmostEqual(targetRegion['width'], 4.6411, places=3)
        self.assertAlmostEqual(targetRegion['height'], 4.0857, places=3)
        self.assertEqual(targetRegion['units'], 'mm')
        # with six.assertRaisesRegex(self, ValueError, 'No mm_x'):
        #     source.convertRegionScale(
        #         sourceRegion, sourceScale, None, targetUnits='mm')

        targetRegion = source.convertRegionScale(sourceRegion,
                                                 sourceScale,
                                                 targetScale,
                                                 targetUnits='pixels')
        self.assertEqual(int(targetRegion['width']), 575)
        self.assertEqual(int(targetRegion['height']), 506)
        self.assertEqual(targetRegion['units'], 'mag_pixels')

        # test getRegionAtAnotherScale
        image, imageFormat = source.getRegionAtAnotherScale(
            sourceRegion,
            sourceScale,
            targetScale,
            format=tilesource.TILE_FORMAT_NUMPY)
        self.assertEqual(imageFormat, tilesource.TILE_FORMAT_NUMPY)
        self.assertTrue(isinstance(image, numpy.ndarray))
        self.assertEqual(image.shape, (506, 575, 4))
        with six.assertRaisesRegex(self, TypeError, 'unexpected keyword'):
            source.getRegionAtAnotherScale(sourceRegion,
                                           sourceScale,
                                           region=sourceRegion,
                                           format=tilesource.TILE_FORMAT_NUMPY)

        # test tileIteratorAtAnotherScale
        tileCount = 0
        for tile in source.tileIteratorAtAnotherScale(
                sourceRegion,
                sourceScale,
                targetScale,
                format=tilesource.TILE_FORMAT_NUMPY):
            tileCount += 1
        self.assertEqual(tileCount, 72)
        with six.assertRaisesRegex(self, TypeError, 'unexpected keyword'):
            for tile in source.tileIteratorAtAnotherScale(
                    sourceRegion,
                    sourceScale,
                    region=sourceRegion,
                    format=tilesource.TILE_FORMAT_NUMPY):
                tileCount += 1
Example #12
0
 def getTileInfo(self, image, params):
     # These endpoints should guarantee that large_image functionality works, so a
     # TileGeneralException can be treated as an internal server error and not get caught
     return ImageItem().getMetadata(image)
Example #13
0
    def testThumbnailFileJob(self):
        from girder.plugins.large_image.models.image_item import ImageItem

        # Create files via a job
        file = self._uploadFile(
            os.path.join(os.environ['LARGE_IMAGE_DATA'], 'sample_image.ptif'))
        itemId = str(file['itemId'])

        # We should report zero thumbnails
        item = Item().load(itemId, user=self.admin)
        present, removed = ImageItem().removeThumbnailFiles(item, keep=10)
        self.assertEqual(present, 0)

        # Test PUT thumbnails
        resp = self.request(method='PUT',
                            path='/large_image/thumbnails',
                            user=self.user)
        self.assertStatus(resp, 403)
        resp = self.request(method='PUT',
                            path='/large_image/thumbnails',
                            user=self.admin)
        self.assertStatus(resp, 400)
        self.assertIn('spec', resp.json['message'])
        self.assertIn('is required', resp.json['message'])
        resp = self.request(method='PUT',
                            path='/large_image/thumbnails',
                            user=self.admin,
                            params={'spec': json.dumps({})})
        self.assertStatus(resp, 400)
        self.assertIn('must be a JSON list', resp.json['message'])

        # Run a job to create two sizes of thumbnails
        self.assertTrue(
            self._createThumbnails([{
                'width': 160,
                'height': 100
            }, {
                'encoding': 'PNG'
            }]))
        # We should report two thumbnails
        present, removed = ImageItem().removeThumbnailFiles(item, keep=10)
        self.assertEqual(present, 2)

        # Run a job to create two sizes of thumbnails, one different than
        # before
        self.assertTrue(
            self._createThumbnails([
                {
                    'width': 160,
                    'height': 100
                },
                {
                    'width': 160,
                    'height': 160
                },
            ]))
        # We should report three thumbnails
        present, removed = ImageItem().removeThumbnailFiles(item, keep=10)
        self.assertEqual(present, 3)

        # Asking for a bad thumbnail specification should just do nothing
        self.assertFalse(self._createThumbnails(['not a dictionary']))
        present, removed = ImageItem().removeThumbnailFiles(item, keep=10)
        self.assertEqual(present, 3)

        # Test GET thumbnails
        resp = self.request(path='/large_image/thumbnails', user=self.user)
        self.assertStatus(resp, 403)
        resp = self.request(path='/large_image/thumbnails',
                            user=self.admin,
                            params={'spec': json.dumps({})})
        self.assertStatus(resp, 400)
        self.assertIn('must be a JSON list', resp.json['message'])
        resp = self.request(path='/large_image/thumbnails', user=self.admin)
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, 3)
        resp = self.request(
            path='/large_image/thumbnails',
            user=self.admin,
            params={'spec': json.dumps([{
                'width': 160,
                'height': 100
            }])})
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, 1)

        # Test DELETE thumbnails
        resp = self.request(method='DELETE',
                            path='/large_image/thumbnails',
                            user=self.user)
        self.assertStatus(resp, 403)
        resp = self.request(method='DELETE',
                            path='/large_image/thumbnails',
                            user=self.admin,
                            params={'spec': json.dumps({})})
        self.assertStatus(resp, 400)
        self.assertIn('must be a JSON list', resp.json['message'])

        # Delete one set of thumbnails
        resp = self.request(method='DELETE',
                            path='/large_image/thumbnails',
                            user=self.admin,
                            params={'spec': json.dumps([{
                                'encoding': 'PNG'
                            }])})
        self.assertStatusOk(resp)
        present, removed = ImageItem().removeThumbnailFiles(item, keep=10)
        self.assertEqual(present, 2)

        # Try to delete some that don't exist
        resp = self.request(
            method='DELETE',
            path='/large_image/thumbnails',
            user=self.admin,
            params={'spec': json.dumps([{
                'width': 200,
                'height': 200
            }])})
        self.assertStatusOk(resp)
        present, removed = ImageItem().removeThumbnailFiles(item, keep=10)
        self.assertEqual(present, 2)

        # Delete them all
        resp = self.request(method='DELETE',
                            path='/large_image/thumbnails',
                            user=self.admin)
        self.assertStatusOk(resp)
        present, removed = ImageItem().removeThumbnailFiles(item, keep=10)
        self.assertEqual(present, 0)

        # We should be able to cancel a job
        slowList = [
            {
                'width': 1600,
                'height': 1000
            },
            {
                'width': 3200,
                'height': 2000
            },
            {
                'width': 1600,
                'height': 1002
            },
            {
                'width': 1600,
                'height': 1003
            },
            {
                'width': 1600,
                'height': 1004
            },
        ]
        self.assertEqual(self._createThumbnails(slowList, cancel=True),
                         'canceled')
        present, removed = ImageItem().removeThumbnailFiles(item, keep=10)
        self.assertLess(present, 3 + len(slowList))
Example #14
0
    def testTileIterator(self):
        from girder.plugins.large_image import tilesource
        from girder.plugins.large_image.models.image_item import ImageItem

        file = self._uploadFile(
            os.path.join(
                os.environ['LARGE_IMAGE_DATA'],
                'sample_jp2k_33003_TCGA-CV-7242-'
                '11A-01-TS1.1838afb1-9eee-4a70-9ae3-50e3ab45e242.svs'))
        itemId = str(file['itemId'])
        item = Item().load(itemId, user=self.admin)
        source = ImageItem().tileSource(item)
        tileCount = 0
        visited = {}
        for tile in source.tileIterator(format=tilesource.TILE_FORMAT_PIL,
                                        scale={'magnification': 5}):
            # Check that we haven't loaded the tile's image yet
            self.assertFalse(getattr(tile, 'loaded', None))
            visited.setdefault(tile['level_x'], {})[tile['level_y']] = True
            tileCount += 1
            self.assertEqual(tile['tile'].size,
                             (tile['width'], tile['height']))
            self.assertEqual(tile['width'],
                             256 if tile['level_x'] < 11 else 61)
            self.assertEqual(tile['height'],
                             256 if tile['level_y'] < 11 else 79)
            # Check that we have loaded the tile's image
            self.assertTrue(getattr(tile, 'loaded', None))
        self.assertEqual(tileCount, 144)
        self.assertEqual(len(visited), 12)
        self.assertEqual(len(visited[0]), 12)
        # Check with a non-native magnfication with exact=True
        tileCount = 0
        for tile in source.tileIterator(scale={
                'magnification': 4,
                'exact': True
        }):
            tileCount += 1
        self.assertEqual(tileCount, 0)
        # Check with a non-native (but factor of 2) magnfication with exact=True
        for tile in source.tileIterator(scale={
                'magnification': 2.5,
                'exact': True
        }):
            tileCount += 1
        self.assertEqual(tileCount, 0)
        # Check with a native magnfication with exact=True
        for tile in source.tileIterator(scale={
                'magnification': 5,
                'exact': True
        }):
            tileCount += 1
        self.assertEqual(tileCount, 144)
        # Check with a non-native magnfication without resampling
        tileCount = 0
        for tile in source.tileIterator(format=tilesource.TILE_FORMAT_PIL,
                                        scale={'magnification': 2}):
            tileCount += 1
            self.assertEqual(tile['tile'].size,
                             (tile['width'], tile['height']))
            self.assertEqual(tile['width'],
                             256 if tile['level_x'] < 11 else 61)
            self.assertEqual(tile['height'],
                             256 if tile['level_y'] < 11 else 79)
        self.assertEqual(tileCount, 144)
        # Check with a non-native magnfication with resampling
        tileCount = 0
        for tile in source.tileIterator(format=tilesource.TILE_FORMAT_PIL,
                                        scale={'magnification': 2},
                                        resample=True):
            tileCount += 1
            self.assertEqual(tile['tile'].size,
                             (tile['width'], tile['height']))
            self.assertEqual(tile['width'],
                             256 if tile['level_x'] < 4 else 126)
            self.assertEqual(tile['height'],
                             256 if tile['level_y'] < 4 else 134)
        self.assertEqual(tileCount, 25)

        # Ask for numpy array as results
        tileCount = 0
        for tile in source.tileIterator(scale={'magnification': 5}):
            tileCount += 1
            self.assertTrue(isinstance(tile['tile'], numpy.ndarray))
            self.assertEqual(tile['tile'].shape,
                             (256 if tile['level_y'] < 11 else 79,
                              256 if tile['level_x'] < 11 else 61, 4))
            self.assertEqual(tile['tile'].dtype, numpy.dtype('uint8'))
        self.assertEqual(tileCount, 144)
        # Ask for either PIL or IMAGE data, we should get PIL data
        tileCount = 0
        for tile in source.tileIterator(scale={'magnification': 5},
                                        format=(tilesource.TILE_FORMAT_PIL,
                                                tilesource.TILE_FORMAT_IMAGE),
                                        encoding='JPEG'):
            tileCount += 1
            self.assertTrue(isinstance(tile['tile'], PIL.Image.Image))
        self.assertEqual(tileCount, 144)
        # Ask for PNGs
        tileCount = 0
        for tile in source.tileIterator(scale={'magnification': 5},
                                        format=tilesource.TILE_FORMAT_IMAGE,
                                        encoding='PNG'):
            tileCount += 1
            self.assertFalse(isinstance(tile['tile'], PIL.Image.Image))
            self.assertEqual(tile['tile'][:len(common.PNGHeader)],
                             common.PNGHeader)
        self.assertEqual(tileCount, 144)

        # Use a ptif to test getting tiles as images
        file = self._uploadFile(
            os.path.join(os.environ['LARGE_IMAGE_DATA'], 'sample_image.ptif'))
        itemId = str(file['itemId'])
        item = Item().load(itemId, user=self.admin)
        source = ImageItem().tileSource(item)
        # Ask for either PIL or IMAGE data, we should get image data
        tileCount = 0
        jpegTileCount = 0
        for tile in source.tileIterator(scale={'magnification': 2.5},
                                        format=(tilesource.TILE_FORMAT_PIL,
                                                tilesource.TILE_FORMAT_IMAGE),
                                        encoding='JPEG'):
            tileCount += 1
            if not isinstance(tile['tile'], PIL.Image.Image):
                self.assertEqual(tile['tile'][:len(common.JPEGHeader)],
                                 common.JPEGHeader)
                jpegTileCount += 1
        self.assertEqual(tileCount, 45)
        self.assertGreater(jpegTileCount, 0)
        # Ask for PNGs
        tileCount = 0
        for tile in source.tileIterator(scale={'magnification': 2.5},
                                        format=tilesource.TILE_FORMAT_IMAGE,
                                        encoding='PNG'):
            tileCount += 1
            self.assertEqual(tile['tile'][:len(common.PNGHeader)],
                             common.PNGHeader)
        self.assertEqual(tileCount, 45)
        # Ask for TIFFs
        tileCount = 0
        for tile in source.tileIterator(scale={'magnification': 2.5},
                                        format=tilesource.TILE_FORMAT_IMAGE,
                                        encoding='TIFF'):
            tileCount += 1
            self.assertEqual(tile['tile'][:len(common.TIFFHeader)],
                             common.TIFFHeader)
        self.assertEqual(tileCount, 45)
        # Test some internal properties
        self.assertEqual(len(source._tiffDirectories), 9)
        info = source._tiffDirectories[-1]._tiffInfo
        self.assertEqual(info['bitspersample'], 8)
        self.assertEqual(info['compression'], 7)
        self.assertEqual(info['imagelength'], 12288)
        self.assertEqual(info['imagewidth'], 58368)
        self.assertEqual(info['istiled'], 1)
        self.assertEqual(info['jpegcolormode'], 0)
        self.assertEqual(info['jpegquality'], 75)
        self.assertEqual(info['jpegtablesmode'], 3)
        self.assertEqual(info['orientation'], 1)
        self.assertEqual(info['photometric'], 6)
        self.assertEqual(info['planarconfig'], 1)
        self.assertEqual(info['samplesperpixel'], 3)
        self.assertEqual(info['tilelength'], 256)
        self.assertEqual(info['tilewidth'], 256)
Example #15
0
    def _updateMinervaMetadata(self, item):
        minerva_metadata = {
            'source_type': 'item'
        }
        for file in self.model('item').childFiles(item=item, limit=0):
            # Check the first few k of a file to see if this might be a
            # geojson timeseries.  Crudely, we expect this to be a json array
            # which contains objects, each of which has at least a geojson
            # element.  This test will fail if there are other elements in the
            # first object that push the geojson element beyond the tested
            # header length.  It could give a false positive, too.  The correct
            # way would be to download and parse the whole file, but that would
            # be more expensive in memory and time.
            headerLen = 2048
            fileHeader = ''
            for headerData in self.model('file').download(file, headers=False, endByte=headerLen)():
                fileHeader = (fileHeader + headerData)[:headerLen]
                if len(fileHeader) >= headerLen:
                    break
            if (fileHeader.lstrip()[:1] == '[' and
                    fileHeader.lstrip()[1:].lstrip()[:1] == '{' and
                    '"geojson"' in fileHeader):
                minerva_metadata['original_type'] = 'geojson-timeseries'
                minerva_metadata['dataset_type'] = 'geojson-timeseries'
                minerva_metadata['original_files'] = [{
                    'name': file['name'], '_id': file['_id']}]
                minerva_metadata['geojson_file'] = {
                    'name': file['name'], '_id': file['_id']}
                minerva_metadata['source'] = {
                    'layer_source': 'GeoJSON'}
                break
            # TODO This switching based on which file is found first is
            # fairly brittle and should only be called after first upload.
            if 'geojson' in file['exts']:
                # we found a geojson, assume this is geojson original
                minerva_metadata['original_type'] = 'geojson'
                minerva_metadata['dataset_type'] = 'geojson'
                minerva_metadata['original_files'] = [{
                    'name': file['name'], '_id': file['_id']}]
                minerva_metadata['geojson_file'] = {
                    'name': file['name'], '_id': file['_id']}
                minerva_metadata['source'] = {
                    'layer_source': 'GeoJSON'}
                break
            elif 'json' in file['exts']:
                minerva_metadata['original_type'] = 'json'
                minerva_metadata['dataset_type'] = 'json'
                minerva_metadata['original_files'] = [{
                    'name': file['name'], '_id': file['_id']}]
                break
            elif 'csv' in file['exts']:
                minerva_metadata['original_type'] = 'csv'
                minerva_metadata['dataset_type'] = 'csv'
                minerva_metadata['original_files'] = [{
                    'name': file['name'], '_id': file['_id']}]
                break
            elif ({'tif', 'tiff'}.intersection(file['exts']) and
                  file['mimeType'] == 'image/tiff'):
                info = ImageItem().tileSource(item).getMetadata()
                if 'srs' in info['sourceBounds'] and info['sourceBounds']['srs']:
                    minerva_metadata['original_type'] = 'tiff'
                    minerva_metadata['dataset_type'] = 'geotiff'
                    minerva_metadata['original_files'] = [{
                        'name': file['name'], '_id': file['_id']}]
                    minerva_metadata['source'] = {
                        'layer_source': 'Tiff'}
                break
        updateMinervaMetadata(item, minerva_metadata)

        return minerva_metadata
Example #16
0
    def testTileIteratorRetiling(self):
        from girder.plugins.large_image import tilesource
        from girder.plugins.large_image.models.image_item import ImageItem

        file = self._uploadFile(
            os.path.join(os.environ['LARGE_IMAGE_DATA'], 'sample_image.ptif'))
        itemId = str(file['itemId'])
        item = Item().load(itemId, user=self.admin)
        source = ImageItem().tileSource(item)

        # Test retiling to 500 x 400
        tileCount = 0
        for tile in source.tileIterator(scale={'magnification': 2.5},
                                        format=tilesource.TILE_FORMAT_PIL,
                                        tile_size={
                                            'width': 500,
                                            'height': 400
                                        }):
            tileCount += 1
            self.assertEqual(tile['tile'].size,
                             (tile['width'], tile['height']))
            self.assertEqual(tile['width'],
                             500 if tile['level_x'] < 7 else 148)
            self.assertEqual(tile['height'],
                             400 if tile['level_y'] < 1 else 368)
        self.assertEqual(tileCount, 16)

        # Test retiling to 300 x 275 with 50 x 40 pixels overlap with trimmed
        # edges
        tileCount = 0
        for tile in source.tileIterator(scale={'magnification': 2.5},
                                        format=tilesource.TILE_FORMAT_PIL,
                                        tile_size={
                                            'width': 300,
                                            'height': 275
                                        },
                                        tile_overlap={
                                            'x': 50,
                                            'y': 40,
                                            'edges': True
                                        }):
            tileCount += 1
            self.assertEqual(tile['tile'].size,
                             (tile['width'], tile['height']))
            self.assertEqual(
                tile['width'], 275 if not tile['level_x'] else
                300 if tile['level_x'] < 14 else 173)
            self.assertEqual(
                tile['height'], 255
                if not tile['level_y'] else 275 if tile['level_y'] < 3 else 83)
            self.assertEqual(tile['tile_overlap']['left'],
                             0 if not tile['level_x'] else 25)
            self.assertEqual(tile['tile_overlap']['right'],
                             25 if tile['level_x'] < 14 else 0)
            self.assertEqual(tile['tile_overlap']['top'],
                             0 if not tile['level_y'] else 20)
            self.assertEqual(tile['tile_overlap']['bottom'],
                             20 if tile['level_y'] < 3 else 0)
        self.assertEqual(tileCount, 60)

        # Test retiling to 300 x 275 with 50 x 40 pixels overlap without
        # trimmed edges
        tileCount = 0
        for tile in source.tileIterator(scale={'magnification': 2.5},
                                        format=tilesource.TILE_FORMAT_PIL,
                                        tile_size={
                                            'width': 300,
                                            'height': 275
                                        },
                                        tile_overlap={
                                            'x': 50,
                                            'y': 40
                                        }):
            tileCount += 1
            self.assertEqual(tile['tile'].size,
                             (tile['width'], tile['height']))
            self.assertEqual(tile['width'],
                             300 if tile['level_x'] < 14 else 148)
            self.assertEqual(tile['height'],
                             275 if tile['level_y'] < 3 else 63)
            self.assertEqual(tile['tile_overlap']['left'],
                             0 if not tile['level_x'] else 25)
            self.assertEqual(tile['tile_overlap']['right'],
                             25 if tile['level_x'] < 14 else 0)
            self.assertEqual(tile['tile_overlap']['top'],
                             0 if not tile['level_y'] else 20)
            self.assertEqual(tile['tile_overlap']['bottom'],
                             20 if tile['level_y'] < 3 else 0)
        self.assertEqual(tileCount, 60)

        # Test retiling to 300 x 275 with 51 x 41 pixels overlap with trimmed
        # edges
        tileCount = 0
        for tile in source.tileIterator(scale={'magnification': 2.5},
                                        format=tilesource.TILE_FORMAT_PIL,
                                        tile_size={
                                            'width': 300,
                                            'height': 275
                                        },
                                        tile_overlap={
                                            'x': 51,
                                            'y': 41,
                                            'edges': True
                                        }):
            tileCount += 1
            self.assertEqual(tile['tile'].size,
                             (tile['width'], tile['height']))
            self.assertEqual(
                tile['width'], 275 if not tile['level_x'] else
                300 if tile['level_x'] < 14 else 187)
            self.assertEqual(
                tile['height'], 255
                if not tile['level_y'] else 275 if tile['level_y'] < 3 else 86)
            self.assertEqual(tile['tile_overlap']['left'],
                             0 if not tile['level_x'] else 25)
            self.assertEqual(tile['tile_overlap']['right'],
                             26 if tile['level_x'] < 14 else 0)
            self.assertEqual(tile['tile_overlap']['top'],
                             0 if not tile['level_y'] else 20)
            self.assertEqual(tile['tile_overlap']['bottom'],
                             21 if tile['level_y'] < 3 else 0)
        self.assertEqual(tileCount, 60)

        # Test retiling to 300 x 275 with 51 x 41 pixels overlap without
        # trimmed edges
        tileCount = 0
        for tile in source.tileIterator(scale={'magnification': 2.5},
                                        format=tilesource.TILE_FORMAT_PIL,
                                        tile_size={
                                            'width': 300,
                                            'height': 275
                                        },
                                        tile_overlap={
                                            'x': 51,
                                            'y': 41
                                        }):
            tileCount += 1
            self.assertEqual(tile['tile'].size,
                             (tile['width'], tile['height']))
            self.assertEqual(tile['width'],
                             300 if tile['level_x'] < 14 else 162)
            self.assertEqual(tile['height'],
                             275 if tile['level_y'] < 3 else 66)
            self.assertEqual(tile['tile_overlap']['left'],
                             0 if not tile['level_x'] else 25)
            self.assertEqual(tile['tile_overlap']['right'],
                             26 if tile['level_x'] < 14 else 0)
            self.assertEqual(tile['tile_overlap']['top'],
                             0 if not tile['level_y'] else 20)
            self.assertEqual(tile['tile_overlap']['bottom'],
                             21 if tile['level_y'] < 3 else 0)
        self.assertEqual(tileCount, 60)
Example #17
0
    def testTileIteratorSingleTile(self):
        from girder.plugins.large_image.models.image_item import ImageItem

        file = self._uploadFile(
            os.path.join(os.environ['LARGE_IMAGE_DATA'], 'sample_image.ptif'))
        itemId = str(file['itemId'])
        item = Item().load(itemId, user=self.admin)
        source = ImageItem().tileSource(item)

        # Test getting a single tile
        sourceRegion = {
            'width': 0.7,
            'height': 0.6,
            'left': 0.15,
            'top': 0.2,
            'units': 'fraction'
        }
        tileCount = 0
        for tile in source.tileIterator(region=sourceRegion,
                                        scale={'magnification': 5},
                                        tile_position=25):
            tileCount += 1
            self.assertEqual(tile['tile_position']['position'], 25)
            self.assertEqual(tile['tile_position']['level_x'], 8)
            self.assertEqual(tile['tile_position']['level_y'], 2)
            self.assertEqual(tile['tile_position']['region_x'], 4)
            self.assertEqual(tile['tile_position']['region_y'], 1)
            self.assertEqual(tile['iterator_range']['level_x_min'], 4)
            self.assertEqual(tile['iterator_range']['level_y_min'], 1)
            self.assertEqual(tile['iterator_range']['level_x_max'], 25)
            self.assertEqual(tile['iterator_range']['level_y_max'], 5)
            self.assertEqual(tile['iterator_range']['region_x_max'], 21)
            self.assertEqual(tile['iterator_range']['region_y_max'], 4)
            self.assertEqual(tile['iterator_range']['position'], 84)
        self.assertEqual(tileCount, 1)
        tiles = list(
            source.tileIterator(region=sourceRegion,
                                scale={'magnification': 5},
                                tile_position={'position': 25}))
        self.assertEqual(len(tiles), 1)
        self.assertEqual(tiles[0]['tile_position']['position'], 25)
        tiles = list(
            source.tileIterator(region=sourceRegion,
                                scale={'magnification': 5},
                                tile_position={
                                    'level_x': 8,
                                    'level_y': 2
                                }))
        self.assertEqual(len(tiles), 1)
        self.assertEqual(tiles[0]['tile_position']['position'], 25)
        tiles = list(
            source.tileIterator(region=sourceRegion,
                                scale={'magnification': 5},
                                tile_position={
                                    'region_x': 4,
                                    'region_y': 1
                                }))
        self.assertEqual(len(tiles), 1)
        self.assertEqual(tiles[0]['tile_position']['position'], 25)
        tiles = list(
            source.tileIterator(region=sourceRegion,
                                scale={'magnification': 5},
                                tile_position={'position': 90}))
        self.assertEqual(len(tiles), 0)
Example #18
0
    def testMagnification(self):
        from girder.plugins.large_image.models.image_item import ImageItem

        file = self._uploadFile(
            os.path.join(
                os.environ['LARGE_IMAGE_DATA'],
                'sample_jp2k_33003_TCGA-CV-7242-'
                '11A-01-TS1.1838afb1-9eee-4a70-9ae3-50e3ab45e242.svs'))
        itemId = str(file['itemId'])
        item = Item().load(itemId, user=self.admin)
        source = ImageItem().tileSource(item)
        mag = source.getNativeMagnification()
        self.assertEqual(mag['magnification'], 40.0)
        self.assertEqual(mag['mm_x'], 0.000252)
        self.assertEqual(mag['mm_y'], 0.000252)
        mag = source.getMagnificationForLevel()
        self.assertEqual(mag['magnification'], 40.0)
        self.assertEqual(mag['mm_x'], 0.000252)
        self.assertEqual(mag['mm_y'], 0.000252)
        self.assertEqual(mag['level'], 7)
        self.assertEqual(mag['scale'], 1.0)
        mag = source.getMagnificationForLevel(0)
        self.assertEqual(mag['magnification'], 0.3125)
        self.assertEqual(mag['mm_x'], 0.032256)
        self.assertEqual(mag['mm_y'], 0.032256)
        self.assertEqual(mag['level'], 0)
        self.assertEqual(mag['scale'], 128.0)
        self.assertEqual(source.getLevelForMagnification(), 7)
        self.assertEqual(source.getLevelForMagnification(exact=True), 7)
        self.assertEqual(source.getLevelForMagnification(40), 7)
        self.assertEqual(source.getLevelForMagnification(20), 6)
        self.assertEqual(source.getLevelForMagnification(0.3125), 0)
        self.assertEqual(source.getLevelForMagnification(15), 6)
        self.assertEqual(source.getLevelForMagnification(25), 6)
        self.assertEqual(source.getLevelForMagnification(15, rounding='ceil'),
                         6)
        self.assertEqual(source.getLevelForMagnification(25, rounding='ceil'),
                         7)
        self.assertEqual(source.getLevelForMagnification(15, rounding=False),
                         5.585)
        self.assertEqual(source.getLevelForMagnification(25, rounding=False),
                         6.3219)
        self.assertEqual(source.getLevelForMagnification(45, rounding=False),
                         7)
        self.assertEqual(source.getLevelForMagnification(15, rounding=None),
                         5.585)
        self.assertEqual(source.getLevelForMagnification(25, rounding=None),
                         6.3219)
        self.assertEqual(source.getLevelForMagnification(45, rounding=None),
                         7.1699)
        self.assertEqual(source.getLevelForMagnification(mm_x=0.0005), 6)
        self.assertEqual(
            source.getLevelForMagnification(mm_x=0.0005, mm_y=0.002), 5)
        self.assertEqual(
            source.getLevelForMagnification(mm_x=0.0005, exact=True), None)
        self.assertEqual(
            source.getLevelForMagnification(mm_x=0.000504, exact=True), 6)
        self.assertEqual(source.getLevelForMagnification(80), 7)
        self.assertEqual(source.getLevelForMagnification(80, exact=True), None)
        self.assertEqual(source.getLevelForMagnification(0.1), 0)