예제 #1
1
 def test_detect_format(self):
     self.assertTrue(
             OpenSlide.detect_format(file_path('__missing_file')) is None)
     self.assertTrue(
             OpenSlide.detect_format(file_path('../setup.py')) is None)
     self.assertEqual(
             OpenSlide.detect_format(file_path('boxes.tiff')),
             'generic-tiff')
예제 #2
1
 def test_operations_on_closed_handle(self):
     osr = OpenSlide(file_path('boxes.tiff'))
     props = osr.properties
     associated = osr.associated_images
     osr.close()
     self.assertRaises(ArgumentError,
             lambda: osr.read_region((0, 0), 0, (100, 100)))
     self.assertRaises(ArgumentError, lambda: osr.close())
     self.assertRaises(ArgumentError, lambda: props['openslide.vendor'])
     self.assertRaises(ArgumentError, lambda: associated['label'])
예제 #3
1
	def __init__(self, root):

		pn = '/Users/nathaning/Documents/Python/Image Processing/B2 H&E 20X_001.svs'
		level = 1
		i = OpenSlide(pn) # Load an SVS file
		# dims = i.level_dimensions[level]
		# k = i.read_region((0,0), level, dims) #Extract the level 1 image as a PIL.Image Object
		k = i.get_thumbnail(size=(600, 600))

		# k.show()

		self.pi = ImageTk.PhotoImage(k)
		disp = Label(root, image=self.pi)
		disp.pack()

		print 'done'
    def read_wsi_normal(wsi_path):
        """
            # =====================================================================================
            # read WSI image and resize
            # Due to memory constraint, we use down sampled (4th level, 1/32 resolution) image
            # ======================================================================================
        """
        try:
            wsi_image = OpenSlide(wsi_path)
            level_used = wsi_image.level_count - 1
            rgb_image = np.array(wsi_image.read_region((0, 0), level_used,
                                                       wsi_image.level_dimensions[level_used]))

        except OpenSlideUnsupportedFormatError:
            print('Exception: OpenSlideUnsupportedFormatError')
            return None, None, None

        return wsi_image, rgb_image, level_used
예제 #5
0
    def read_tumor_wsi(self, wsi_path, mask_path):
        """
            # =====================================================================================
            # read WSI image and resize
            # Due to memory constraint, we use down sampled (4th level, 1/32 resolution) image
            # ======================================================================================
        """
        try:
            self.wsi_path = wsi_path
            self.wsi_image = OpenSlide(wsi_path)
            self.mask_image = OpenSlide(mask_path)

            level_used = self.wsi_image.level_count - 1

            self.rgb_image_pil = self.wsi_image.read_region((0, 0), level_used,
                                                            self.wsi_image.level_dimensions[level_used])
            self.rgb_image = np.array(self.rgb_image_pil)

            mask_level = self.mask_image.level_count - 1
            self.rgb_mask_pil = self.mask_image.read_region((0, 0), mask_level,
                                                            self.mask_image.level_dimensions[mask_level])

            resize_factor = float(1.0 / pow(2, level_used - mask_level))
            self.mask = cv2.resize(np.array(self.rgb_mask_pil), (0, 0), fx=resize_factor, fy=resize_factor)
            # self.rgb_image = cv2.resize(self.rgb_image, (0, 0), fx=0.50, fy=0.50)
        except OpenSlideUnsupportedFormatError:
            print('Exception: OpenSlideUnsupportedFormatError')
            return False

        return True
    def read_wsi_mask(mask_path, level=def_level):
        try:
            wsi_mask = OpenSlide(mask_path)

            mask_image = np.array(wsi_mask.read_region((0, 0), level,
                                                       wsi_mask.level_dimensions[level]))

        except OpenSlideUnsupportedFormatError:
            print('Exception: OpenSlideUnsupportedFormatError')
            return None, None

        return wsi_mask, mask_image
    def next_batch(self, n, **kwargs):
        assert self.initialized == True, "Data Source not initialized"

        flat = 'flat' in kwargs and kwargs['flat'] is True
        noise = 'noise' in kwargs and kwargs['noise'] is True
        nc = kwargs['nc'] if 'nc' in kwargs else 0.05
        level = kwargs['level'] if 'level' in kwargs else 0
        isfloat = kwargs['isfloat'] if 'isfloat' in kwargs else False

        selected_image = np.random.randint(len(self.images))
        chunks = np.random.random((3,n))

        im_path = self.images[selected_image][0]
        osr = OpenSlide(im_path)
        mask = self.masks[selected_image]
        imsize = osr.level_dimensions[level]
        ratios = [imsize[0]*1./mask.shape[0], imsize[1]*1./mask.shape[1]]

        n_px_in_mask = mask.sum()
        indexes = np.arange(n_px_in_mask)+1
        mask_indexes = np.zeros(mask.shape)
        mask_indexes[mask] = indexes

        chunks[0,:] *= n_px_in_mask # index in mask
        chunks[1,:] *= (ratios[0]-self.chunksize[0])    # y pixel offset in higher def image from top-left of region
        chunks[2,:] *= (ratios[1]-self.chunksize[1])    # x pixel offset in higher def image from top-left of region
        if isfloat:
            chunks = chunks.astype('float')
            if chunks.max() > 1:
                chunks = chunks / 255.
        else:
            if chunks.max() < 1:
                chunks = chunks*255
            chunks = np.round(chunks).astype('uint16')

        lowres_coordinates = [np.where(mask_indexes==c) for c in chunks[0,:]]
        highres_coordinates = [ ( int((lr[0]*ratios[0] + chunks[1,i])[0]), int((lr[1]*ratios[1] + chunks[2,i])[0]) ) for i,lr in enumerate(lowres_coordinates) ]

        if noise:
            if flat:
                toAdd = np.random.rand(n, self.chunksize[0]*self.chunksize[1]*3)*nc
            else:
                toAdd = np.random.rand(n, self.chunksize[0], self.chunksize[1], 3)*nc
        else:
            if flat:
                toAdd = np.zeros((n, self.chunksize[0]*self.chunksize[1]*3))
            else:
                toAdd = np.zeros((n, self.chunksize[0], self.chunksize[1], 3))

        if flat :
            return [np.asarray(osr.read_region((chunk[0], chunk[1]), level, self.chunksize)).flatten().astype(np.float32)[:,:,:3]/255.+toAdd[i] for i,chunk in enumerate(highres_coordinates)]
        else:
            return [np.asarray(osr.read_region((chunk[0], chunk[1]), level, self.chunksize)).astype(np.float32)[:,:,:3]/255.+toAdd[i] for i,chunk in enumerate(highres_coordinates)]
예제 #8
0
    def initUI(self):      
        # initialize the widget, make the openslide object pointing to the
        # multilevel image and initialize the view to the top left corner
        
        archivo=u'/home/martin/Downloads/CMU-1-JP2K-33005.svs'
        # openSlide object
        self.osr = OS(archivo)
        self.level_count = self.osr.level_count
        self.current_x=0
        self.current_y=0
        self.current_zoom=self.level_count-1
        self.level_dimensions=self.osr.level_dimensions
        print self.level_dimensions
        print self.osr.level_downsamples
        #width, height = osr.dimensions

        

        

        self.hbox.addWidget(self.lbl)
        
        
        #self.move(300, 200)

        
        self.updatePixmap()
        self.show()
예제 #9
0
	def get(self, id):
		"""
        Get slide thumbnail
        ---
        tags:
          - Thumbnail
        parameters:
          - in: path
            name: id
            description: MonogDB ObjectId -- Example 57bf3c092f9b2e1595b29730
            type: string
          - in: query
            name: size
            description: Thumbnail size [small, medium, large]
            type: string
        responses:
          200:
            description: Returns the slide information
          404:
          	description: Invalid slide Id or slide not found
        """

		if not ObjectId.is_valid(id):
			resp = {"status": 404, "message": "Invalid slide Id " + id}
			return Response(dumps(resp), status=404, mimetype='application/json')

		thumbSize = request.args.get("size", "small")
		image = self.slides.find_one({'_id': ObjectId(id)})
		path = image["path"]
		filename = os.path.splitext(os.path.basename(path))[0] + "." + str(thumbSize) + ".jpg"

		if not self.gfs.exists(filename=filename):
			width = int(image["scanProperties"]["openslide_level[0]_width"])
			height = int(image["scanProperties"]["openslide_level[0]_height"])
			thumbHeight = float(self.config["thumb_" + thumbSize + "_height"])
			thumbWidth = int(round(thumbHeight/float(height) * int(width)))

			try:
				osr = OpenSlide(path)
				thumb = osr.get_thumbnail((thumbWidth,thumbHeight))
			except OpenSlideError, e:
				resp = {"status": 404, "message": "OpenSlideError: Thumbnail failed to load"}
				return Response(dumps(resp), status=404, mimetype='application/json')
			except ValueError:
				resp = {"status": 404, "message": "ValueError: Thumbnail failed to load"}
				return Response(dumps(resp), status=404, mimetype='application/json')
    def read_wsi_mask(self, wsi_path, mask_path):
        try:
            self.cur_wsi_path = wsi_path
            self.wsi_image = OpenSlide(wsi_path)
            self.mask_image = OpenSlide(mask_path)

            self.level_used = min(self.def_level, self.wsi_image.level_count - 1, self.mask_image.level_count - 1)

            self.mask_pil = self.mask_image.read_region((0, 0), self.level_used,
                                                            self.mask_image.level_dimensions[self.level_used])
            self.mask = np.array(self.mask_pil)

        except OpenSlideUnsupportedFormatError:
            print('Exception: OpenSlideUnsupportedFormatError')
            return False

        return True
 def __init__(self, basedir, relpath=''):
     self.name = os.path.basename(relpath)
     self.children = []
     for name in sorted(os.listdir(os.path.join(basedir, relpath))):
         cur_relpath = os.path.join(relpath, name)
         cur_path = os.path.join(basedir, cur_relpath)
         if os.path.isdir(cur_path):
             cur_dir = _Directory(basedir, cur_relpath)
             if cur_dir.children:
                 self.children.append(cur_dir)
         elif OpenSlide.detect_format(cur_path):
             self.children.append(_SlideFile(cur_relpath))
    def read_wsi_tumor(wsi_path, mask_path):
        """
            # =====================================================================================
            # read WSI image and resize
            # Due to memory constraint, we use down sampled (4th level, 1/32 resolution) image
            # ======================================================================================
        """
        try:
            wsi_image = OpenSlide(wsi_path)
            wsi_mask = OpenSlide(mask_path)

            level_used = wsi_image.level_count - 1

            rgb_image = np.array(wsi_image.read_region((0, 0), level_used,
                                                       wsi_image.level_dimensions[level_used]))

            mask_level = wsi_mask.level_count - 1
            mask_image = wsi_mask.read_region((0, 0), mask_level,
                                              wsi_image.level_dimensions[mask_level])
            resize_factor = float(1.0 / pow(2, level_used - mask_level))
            # print('resize_factor: %f' % resize_factor)
            mask_image = cv2.resize(np.array(mask_image), (0, 0), fx=resize_factor, fy=resize_factor)

            wsi_mask.close()
        except OpenSlideUnsupportedFormatError:
            print('Exception: OpenSlideUnsupportedFormatError')
            return None, None, None, None

        return wsi_image, rgb_image, mask_image, level_used
예제 #13
0
def walk_slides(pool, tempdir, in_root, in_relpath, out_root, out_relpath):
    """Build a directory of tiled images from a directory of slides."""
    slides = []
    for in_name in sorted(os.listdir(os.path.join(in_root, in_relpath))):
        in_cur_relpath = os.path.join(in_relpath, in_name)
        in_cur_path = os.path.join(in_root, in_cur_relpath)
        out_name = os.path.splitext(in_name)[0]
        out_cur_relpath = os.path.join(out_relpath, out_name.lower())
        if OpenSlide.can_open(in_cur_path):
            slides.append(tile_slide(pool, in_cur_relpath, in_cur_path,
                        out_name, out_root, out_cur_relpath))
        elif os.path.splitext(in_cur_path)[1] == '.zip':
            temp_path = mkdtemp(dir=tempdir)
            print 'Extracting %s...' % out_cur_relpath
            zipfile.ZipFile(in_cur_path).extractall(path=temp_path)
            for sub_name in os.listdir(temp_path):
                sub_path = os.path.join(temp_path, sub_name)
                if OpenSlide.can_open(sub_path):
                    slides.append(tile_slide(pool, in_cur_relpath, sub_path,
                                out_name, out_root, out_cur_relpath))
                    break
    return slides
def generate_thumbnail(image_filepath, thumbnail_filepath):
    '''
    Generates a thumbnail from the specified image.
    '''

    # open image with OpenSlide library
    image_file = OpenSlide(image_filepath)
    
    # extract image dimensions
    image_dims = image_file.dimensions
    
    # make thumbnail 100 times smaller
    thumb_dims = tuple( (x/100 for x in image_dims) )
    
    # create thumbnail
    thumb_file = image_file.get_thumbnail(thumb_dims)
    
    # save file with desired path, format
    thumb_file.save(thumbnail_filepath, "png")
    
    # cleanup
    image_file.close()
예제 #15
0
def getThumbnail(path):
    """This will return the 0/0 tile later whch in the case of an SVS image is actually the thumbnail..... """

    path = os.path.abspath(os.path.join(dz.config['slides_dir'], path))
    osr = OpenSlide(path)
    format = 'jpeg'

    format = format.lower()
    if format != 'jpeg' and format != 'png':
        # Not supported by Deep Zoom
        abort(404)
    try:
        thumb = osr.get_thumbnail( (300,300))
    except ValueError:
        # Invalid level or coordinates
        abort(404)

    buf = PILBytesIO()
    thumb.save(buf, 'jpeg', quality=90)
    resp = make_response(buf.getvalue())
    resp.mimetype = 'image/%s' % format
    return resp
    def read_wsi_tumor(self, wsi_path, mask_path):
        """
            # =====================================================================================
            # read WSI image and resize
            # Due to memory constraint, we use down sampled (4th level, 1/32 resolution) image
            # ======================================================================================
        """
        try:
            self.cur_wsi_path = wsi_path
            self.wsi_image = OpenSlide(wsi_path)
            self.mask_image = OpenSlide(mask_path)

            self.level_used = min(self.def_level, self.wsi_image.level_count - 1, self.mask_image.level_count - 1)

            self.rgb_image_pil = self.wsi_image.read_region((0, 0), self.level_used,
                                                            self.wsi_image.level_dimensions[self.level_used])
            self.rgb_image = np.array(self.rgb_image_pil)

        except OpenSlideUnsupportedFormatError:
            print('Exception: OpenSlideUnsupportedFormatError')
            return False

        return True
    def initUI(self):      
        # initialize the widget, make the openslide object pointing to the
        # multilevel image and initialize the view to the top left corner

        if self.filename is not None:
            # openSlide object
            self.osr = OS(self.filename)
            self.level_count = self.osr.level_count
            self.current_x=0
            self.current_y=0
            self.current_zoom=self.level_count-1
            self.level_dimensions=self.osr.level_dimensions
            self.step =int(64*self.osr.level_downsamples[self.current_zoom])
            self.hbox.addWidget(self.lbl)
            self.updatePixmap()
            self.show()
            self.resizeLock=False
예제 #18
0
    def read_normal_wsi(self, wsi_path):
        """
            # =====================================================================================
            # read WSI image and resize
            # Due to memory constraint, we use down sampled (4th level, 1/32 resolution) image
            # ======================================================================================
        """
        try:
            self.wsi_path = wsi_path
            self.wsi_image = OpenSlide(wsi_path)

            level = min(self.def_level, self.wsi_image.level_count - 1)
            print('level used: %d' % level)
            print(self.wsi_image.level_dimensions[level])

            self.rgb_image_pil = self.wsi_image.read_region((0, 0), level,
                                                            self.wsi_image.level_dimensions[level])
            self.rgb_image = np.array(self.rgb_image_pil)

        except OpenSlideUnsupportedFormatError:
            print('Exception: OpenSlideUnsupportedFormatError')
            return False

        return True
예제 #19
0
class _SlideTest(object):
    def setUp(self):
        self.osr = OpenSlide(file_path(self.FILENAME))

    def tearDown(self):
        self.osr.close()
예제 #20
0
def load_slide():
    slidefile = app.config['DEEPZOOM_SLIDE']
    if slidefile is None:
        raise ValueError('No slide file specified')
    app.slide = OpenSlide(slidefile)
    app.dz = DeepZoomGenerator(app.slide)
예제 #21
0
class WSIData:
    def __init__(
        self,
        tif_path,
        centre,
        is_excluded,
        resource_group,
        label_tif_path=None,
        label_xml_path=None,
        patient=None,
    ):
        self._wsi_slide = OpenSlide(str(tif_path))
        self._tif_path = tif_path
        self._is_excluded = is_excluded
        self._label_tif_path = label_tif_path
        self._label_xml_path = label_xml_path
        self._label_slide = None
        self._patient = patient
        self._resource_group = resource_group

        if not isinstance(centre, _StainNormalizer.Centre):
            raise TypeError('centre must be an instance of {}.Centre.'.format(
                self.__class__.__name__))
        self._centre = centre
        self._name = tif_path.stem

    def _get_label_slide(self):
        if self._label_slide is None and self._label_tif_path is not None:
            self._label_slide = (self._label_tif_path
                                 and OpenSlide(str(self._label_tif_path)))
        return self._label_slide

    @staticmethod
    def _threshold_sv(img_np):
        '''Performs thresholding on the WSI image to extract the tissue region.

        RGB image is converted to HSV color space. The H and S channels are
        then thresholded via Otsu's Threshold, then combined via bitwise AND.
        Morphological transormation was applied by removing small holes and
        regions, and was filtered using median blur.

        Parameters
        ----------
        img_np: np.uint8[H, W, 3] np.array
            RGB WSI as an np.array image

        Returns
        -------
        bool[H, W] np.array
            ROI mask of the WSI.
        '''
        img_hsv = rgb2hsv(img_np)
        # channel_h = img_hsv[:, :, 0]
        channel_s = img_hsv[:, :, 1]
        channel_v = img_hsv[:, :, 2]

        # thresh_h = threshold_otsu(channel_h)
        thresh_s = threshold_otsu(channel_s)
        thresh_v = threshold_otsu(channel_v)

        # binary_h = channel_h > thresh_h
        binary_s = channel_s > min(thresh_s, 0.1)
        binary_v = channel_s > min(thresh_v, 0.2)

        # binary = np.bitwise_and(binary_h, binary_s)
        binary = np.bitwise_and(binary_s, binary_v)
        binary = morphology.remove_small_objects(binary, _SMALL_OBJECT_AREA)
        binary = morphology.remove_small_holes(binary, _SMALL_HOLE_AREA)
        binary = median(binary, morphology.disk(_MEDIAN_DISK))

        return binary.astype(bool)

    @staticmethod
    def _threshold_hs(img_np):
        '''Performs thresholding on the WSI image to extract the tissue region.

        RGB image is converted to HSV color space. The H and S channels are
        then thresholded via Otsu's Threshold, then combined via bitwise AND.
        Morphological transormation was applied by removing small holes and
        regions, and was filtered using median blur.

        Parameters
        ----------
        img_np: np.uint8[H, W, 3] np.array
            RGB WSI as an np.array image

        Returns
        -------
        bool[H, W] np.array
            ROI mask of the WSI.
        '''
        img_hsv = rgb2hsv(img_np)
        channel_h = img_hsv[:, :, 0]
        channel_s = img_hsv[:, :, 1]

        thresh_h = threshold_otsu(channel_h)
        thresh_s = threshold_otsu(channel_s)

        binary_h = channel_h > thresh_h
        binary_s = channel_s > thresh_s

        binary = np.bitwise_and(binary_h, binary_s)
        binary = morphology.remove_small_objects(binary, _SMALL_OBJECT_AREA)
        binary = morphology.remove_small_holes(binary, _SMALL_HOLE_AREA)
        binary = median(binary, morphology.disk(_MEDIAN_DISK))

        return binary.astype(bool)

    @staticmethod
    def _threshold_gray(img_np):
        binary = np.full(img_np.shape[:2], False)
        binary[np.where(rgb2gray(img_np) < 0.8)] = True
        binary = morphology.remove_small_objects(binary, _SMALL_OBJECT_AREA)
        binary = morphology.remove_small_holes(binary, _SMALL_HOLE_AREA)
        binary = median(binary, morphology.disk(_MEDIAN_DISK))
        return binary

    def _roi_threshold(self, img_np):
        # return self._threshold_sv(img_np)
        # return self._threshold_gray(img_np)
        return self._threshold_hs(img_np)

    def _mark_metastases_regions_in_label(self, blank_mask_np, label_np):
        '''Marks the blank mask using the given label image.

        This is to be overriden due to the different nature of the labels
        from the CAMELYON 16 and 17 data set.

        Parameters
        ----------
        blank_mask_np: bool[H, W] np.array
            Mask to serve as the new label

        label_np: np.uint[H, W] np.array
            Gray scale image with the mask values.

        Returns
        -------
        bool[H, W] np.array
            Mask to serve as the new label
        '''
        blank_mask_np[np.where(label_np == 1)] = True
        blank_mask_np[np.where(label_np == 2)] = False

    @property
    def name(self):
        return self._name

    @property
    def centre(self):
        return self._centre

    @property
    def label_xml_path(self):
        return self._label_xml_path

    @property
    def tif_path(self):
        return self._tif_path

    @property
    def is_excluded(self):
        return self._is_excluded

    @property
    def patient(self):
        return self._patient

    @property
    def resource_group(self):
        return self._resource_group

    def get_full_wsi_image(self, level):
        '''Returns the whole WSI as an RGB image.

        Parameters
        ----------
        level: int
            Level downsample to read the WSI. (values: 0..8)

        Returns
        -------
        np.uint8[H, W, 3] np.array
            Whole WSI RGB image.
        '''
        wsi_dim = self._wsi_slide.level_dimensions[level]
        wsi_img = self._wsi_slide.read_region((0, 0), level, wsi_dim)
        return np.array(wsi_img.convert('RGB'))

    def get_level_dimension(self, level):
        '''Returns the dimensions of the WSI for a given level.

        Parameters
        ----------
        level: int
            Level downsample to get dimension. (values: 0..8)

        Returns
        -------
        (width: int, height: int)
            Dimension of the WSI.
        '''
        return self._wsi_slide.level_dimensions[level]

    def get_level_downsample(self, level):
        '''Returns the dimensions of the WSI for a given level.

        Parameters
        ----------
        level: int
            Level downsample to get dimension. (values: 0..8)

        Returns
        -------
        (width: int, height: int)
            Dimension of the WSI.
        '''
        return self._wsi_slide.level_downsamples[level]

    def get_roi_mask(self, level):
        '''Returns the ROI of the WSI i.e. the tissue region.

        Parameters
        ----------
        level: int
            Level downsample to read the WSI. (values: 0..8)

        Returns
        -------
        bool[H, W] np.array
            Tissue ROI mask of the WSI.
        '''
        wsi_img = self.get_full_wsi_image(level)
        wsi_img_np = np.array(wsi_img, dtype=np.uint8)
        roi_mask = self._roi_threshold(wsi_img_np)
        metastases_roi_mask, label_np = self._get_metastases_mask(level)
        roi_mask[np.where(metastases_roi_mask)] = True
        roi_mask[np.where(label_np == 3)] = False
        return roi_mask

    def _get_metastases_mask(self, level):
        '''Get metastases ROI of the WSI.

        Parameters
        ----------
        level: int
            Level downsample to read the WSI. (values: 0..8)

        Returns
        -------
        bool[H, W] np.array
            Metastases ROI mask of the WSI.
        '''
        wsi_w, wsi_h = self._wsi_slide.level_dimensions[level]
        metastases_mask = np.full((wsi_h, wsi_w), False)

        label_slide = self._get_label_slide()
        if label_slide is not None:
            label_dim = label_slide.level_dimensions[level]
            label_img = label_slide.read_region((0, 0), level, label_dim)
            label_np = np.array(label_img.convert('L'))
            label_w, label_h = label_dim
            label_np = label_np[:min(wsi_h, label_h), :min(wsi_w, label_w)]
            self._mark_metastases_regions_in_label(metastases_mask, label_np)
        else:
            label_np = np.full((wsi_h, wsi_w), 0)

        return metastases_mask, label_np

    def get_metastases_mask(self, level):
        return self._get_metastases_mask(level)[0]

    def read_region_and_label(self, coordinates, level, dimension):
        '''Extracts a RGB region from the WSI.

        The given coordinates will be the center of the region, with the
        given dimension.

        Parameters
        ----------
        coordinates: (x: int, y: int)
            Coordinates in the WSI at level 0. Upper-left of the region.

        level: int
            Level downsample to read the WSI. (values: 0..8)

        dimension: (w: int, h: int)
            Dimension of the region to extract.

        Returns
        -------
        np.uint8[H, W, 3] np.array
            RGB region from WSI.

        bool[H, W] np.array
            Label mask for the given region.
        '''
        scale_factor = 2**level
        w, h = dimension
        w_0, h_0 = w * scale_factor, h * scale_factor
        x, y = coordinates

        ## coordinate is at the center of the patches
        # x, y = x - (w * 2**level // 2), y - (h * 2**level // 2)
        args = (x, y), 0, (w_0, h_0)
        patch_img = self._wsi_slide.read_region(*args)
        patch_np = np.array(patch_img.convert('RGB'))
        patch_np = resize(patch_np, dimension, mode='reflect')

        metastases_np = np.full((w, h), False)

        label_slide = self._get_label_slide()
        if label_slide is not None:
            label_img = label_slide.read_region(*args)
            label_np = np.array(label_img.convert('L'))
            label_np = label_np[::scale_factor, ::scale_factor]
            self._mark_metastases_regions_in_label(metastases_np, label_np)

        return patch_np, metastases_np

    def _get_roi_patch_positions(self,
                                 level,
                                 get_roi,
                                 stride=256,
                                 patch_side=513,
                                 ds_level=5):
        '''Positions returned are in level 0.'''
        assert ds_level > level, 'level must be less than ds_level'

        width, height = self._wsi_slide.level_dimensions[level]
        ds_roi = get_roi(ds_level)
        ds = 2**(ds_level - level)
        upscale_factor = 2**level

        for y in range(0, math.ceil(height / stride) * stride, stride):
            for x in range(0, math.ceil(width / stride) * stride, stride):
                y_ds = y // ds
                x_ds = x // ds
                y_ds_end = (y + stride) // ds
                x_ds_end = (x + stride) // ds
                roi_patch = ds_roi[y_ds:y_ds_end, x_ds:x_ds_end]

                if (np.sum(roi_patch) / roi_patch.size >
                        _ROI_PATCH_COVER_PERCENTAGE):
                    yield x * upscale_factor, y * upscale_factor

    def get_roi_patch_positions(self,
                                level,
                                stride=256,
                                patch_side=513,
                                ds_level=5,
                                force_not_excluded=False):
        if not self._is_excluded or force_not_excluded:
            get_roi = self.get_roi_mask
        else:
            get_roi = self.get_metastases_mask

        return self._get_roi_patch_positions(
            level,
            get_roi,
            stride,
            patch_side,
            ds_level,
        )

    def close(self):
        self._wsi_slide.close()
        self._label_slide is not None and self._label_slide.close()

    def __repr__(self):
        return '<Centre: {}, Name: {}>'.format(self._centre, self._name)
예제 #22
0
if __name__ == "__main__":
    svs = []
    for filename in os.listdir("./GBM_TOP/"):
        svs.append(filename)

    slide_counter = 0
    for num in range(0, len(svs)):  # len(svs)):

        temp_svs = "./GBM_TOP/" + str(
            svs[num]
        )  # patches collected already from 1004347, 1004366, 1004346"
        # print(temp_xm

        print(temp_svs)
        Sample_list = total_data()
        if str(svs[num][:15]) in Sample_list:
            path = "./GBM_top_patches2/Pretrain11/" + str(svs[num][:15])
            print(path)

            try:
                os.mkdir(path)
                print(num)
                slide = OpenSlide(temp_svs)
                patches = reading_WSI(slide=slide)
                path_extraction(patches, path)
            except:
                print('already_exist')
                # print(a)
        else:
            print("%s:::doesnotexist" % str(svs[num]))
예제 #23
0
    parser = ArgumentParser()
    parser.add_argument("--level", type=int, default=11)
    parser.add_argument("--x", type=int, default=0)
    parser.add_argument("--y", type=int, default=2)
    parser.add_argument("--file-path",
                        type=str,
                        default="/files/data/CMU-1.svs")
    parser.add_argument("--output-file-path",
                        type=str,
                        default="/files/output/out.jpeg")
    parser.add_argument("--img-format", type=str, default="jpeg")
    parser.add_argument("--img-quality", type=int, default=100)
    args = parser.parse_args()

    file_path = Path(args.file_path).expanduser()
    slide = OpenSlide(str(file_path))
    mpp_x = slide.properties[PROPERTY_NAME_MPP_X]
    mpp_y = slide.properties[PROPERTY_NAME_MPP_Y]

    dzg = DeepZoomGenerator(
        slide,
        tile_size=DEEPZOOM_TILESIZE,
        overlap=DEEPZOOM_OVERLAP,
        limit_bounds=DEEPZOOM_LIMIT_BOUNDS,
    )

    location = (args.x, args.y)
    region = dzg.get_tile(args.level, location)
    region.save(args.output_file_path,
                format=args.img_format,
                quality=args.img_quality)
예제 #24
0
 def __init__(self, path: str, tilesize: int = 512):
     self._slide = OpenSlide(path)
     self._tilesize = tilesize
     self._store = create_meta_store(self._slide, tilesize)
예제 #25
0
def get_bounds(patches, slide_location):
      
    """
    Input: Image patches as dictionary of n keys with matrix of (Y,X,Z) Coordinates per patch
    Output: an image mask for each valid bounding box 
    """
    slide = OpenSlide(slide_location)
    print(slide.level_dimensions)
    slide_size = slide.level_dimensions[0] 
    #mask_zero = np.zeros(shape = slide_size, dtype=float)
    boxes = []
    masks = []
    values = patches.values()
    i = 0
    
    mask =PIL.Image.new('L', slide_size, 0)
    good_region_mask= PIL.Image.new('L', slide_size, 1)
    
    for patch in values:
        first_coord = patch[0]
        last_coord = patch[len(patch)-1]
        
        area = abs(first_coord[0]-last_coord[0])* abs(first_coord[1]-last_coord[1])
        
        
            
        if area < 40000:  # annotation is circle
              
            y_max = max(patch[:,0])
            y_min = min(patch[:,0])
            
            x_max = max(patch[:,1])
            x_min = min(patch[:,1])
            
            #make sure annotations are in slide scope
           # if max(patch[:,1])< slide_size[0]:
            #draw the polygon on the mask and fill with ones
           
           # print ((patch[:,0]))
           # print((patch[:,1]))
            ImageDraw.Draw(mask).polygon(zip(patch[:,1],patch[:,0]), outline=1, fill=1)
            
            #store the result in mask_result for further computation
            mask_result = np.array(mask)
            
            #change the outline and fill to white for further use
            ImageDraw.Draw(good_region_mask).polygon(zip(patch[:,1],patch[:,0]), outline=0, fill=0)
                    
            
            #resize  the mask to the region of interest dimensions
            
            mask_result = mask_result[y_min:y_max,x_min:x_max]
            #mask_result = np.expand_dims(mask_result, axis = 3)
            mask_result = cv2.cvtColor(mask_result, cv2.COLOR_GRAY2RGB)
            
            #mask_result = mask_result
            
            
            
            this_region = slide.read_region((x_min,y_min),0,(x_max-x_min , y_max-y_min)).convert('RGB')
            this_region.save("o"+str(i)+".png")
            this_region = cv2.imread("o"+str(i)+".png")#np.array(this_region)
       
           #     print("Error ============> Annotations out of bounds for slide"+str(slide_location)+str(max(patch[:,0]))+"slide size==>"+str(slide_size[1]))
            
            print ("Original croped mask shape {}".format(mask_result.shape))
            print ("Original croped region shape {}".format(this_region.shape))
            
            if mask_result.shape == this_region.shape:
                result = np.multiply(mask_result,this_region)
                boxes.append(result)
                masks.append(mask_result)
                
            else:
                print("slide "+str(i)+" shape is not equal")
            i = i+1 
        else:
            #change the outline and fill to white for further use
            ImageDraw.Draw(good_region_mask).rectangle([(min(patch[:,1])-100,min(patch[:,0])-1000),(max(patch[:,1])+1000,max(patch[:,0])+1000)], outline=0, fill=0)
                    
        
    return boxes, good_region_mask, slide, values 
예제 #26
0
def tile(image_file, outdir, path_to_slide="../Neutrophil/"):
    slide = OpenSlide(path_to_slide + image_file)

    assert 'openslide.bounds-height' in slide.properties
    assert 'openslide.bounds-width' in slide.properties
    assert 'openslide.bounds-x' in slide.properties
    assert 'openslide.bounds-y' in slide.properties

    x = int(slide.properties['openslide.bounds-x'])
    y = int(slide.properties['openslide.bounds-y'])
    bounds_height = int(slide.properties['openslide.bounds-height'])
    bounds_width = int(slide.properties['openslide.bounds-width'])

    half_width_region = 49
    full_width_region = 299
    stepsize = full_width_region - half_width_region

    n_x = int((bounds_width - 1) / stepsize)
    n_y = int((bounds_height - 1) / stepsize)

    residue_x = int((bounds_width - n_x * stepsize) / 50)
    residue_y = int((bounds_height - n_y * stepsize) / 50)
    lowres = slide.read_region(
        (x, y), 2, (int(n_x * stepsize / 16), int(n_y * stepsize / 16)))
    lowres = np.array(lowres)[:, :, :3]

    imloc = []
    counter = 0
    svcounter = 0

    if not os.path.exists(outdir):
        os.makedirs(outdir)

    for i in range(n_x - 1):
        for j in range(n_y - 1):
            target_x = stepsize * i
            target_y = stepsize * j

            image_x = target_x + x
            image_y = target_y + y

            the_image = slide.read_region(
                (image_x, image_y), 0, (full_width_region, full_width_region))
            the_imagea = np.array(the_image)[:, :, :3]
            the_imagea = np.nan_to_num(the_imagea)
            mask = (the_imagea[:, :, :3] > 200).astype(np.uint8)
            maskb = (the_imagea[:, :, :3] < 5).astype(np.uint8)
            mask = mask[:, :, 0] * mask[:, :, 1] * mask[:, :, 2]
            maskb = maskb[:, :, 0] * maskb[:, :, 1] * maskb[:, :, 2]
            white = (np.sum(mask) + np.sum(maskb)) / (299 * 299)

            if white < 0.5:
                the_image.save(
                    outdir +
                    "/region_x-{}-y-{}.png".format(target_x, target_y))
                strr = outdir + "/region_x-{}-y-{}.png".format(
                    target_x, target_y)
                imloc.append(
                    [svcounter, counter, target_x, target_y, i, j, strr])
                svcounter += 1
            else:
                pass
                # print('Ignore white!')
            counter += 1

    imlocpd = pd.DataFrame(
        imloc, columns=["Num", "Count", "X", "Y", "X_pos", "Y_pos", "Loc"])
    imlocpd.to_csv(outdir + "/dict.csv", index=False)

    return n_x, n_y, lowres, residue_x, residue_y
예제 #27
0
class WSI(object):
    """
        # ================================
        # Class to annotate WSIs with ROIs
        # ================================

    """
    index = 0
    negative_patch_index = 118456
    positive_patch_index = 2230
    wsi_paths = []
    mask_paths = []
    def_level = 7
    key = 0

    def extract_patches_mask(self, bounding_boxes):
        """
        Extract positive patches targeting annotated tumor region

        Save extracted patches to desk as .png image files

        :param bounding_boxes: list of bounding boxes corresponds to tumor regions
        :return:

        """
        mag_factor = pow(2, self.level_used)

        print('No. of ROIs to extract patches from: %d' % len(bounding_boxes))

        for i, bounding_box in enumerate(bounding_boxes):
            b_x_start = int(bounding_box[0]) * mag_factor
            b_y_start = int(bounding_box[1]) * mag_factor
            b_x_end = (int(bounding_box[0]) + int(bounding_box[2])) * mag_factor
            b_y_end = (int(bounding_box[1]) + int(bounding_box[3])) * mag_factor
            X = np.random.random_integers(b_x_start, high=b_x_end, size=500)
            Y = np.random.random_integers(b_y_start, high=b_y_end, size=500)
            # X = np.arange(b_x_start, b_x_end-256, 5)
            # Y = np.arange(b_y_start, b_y_end-256, 5)

            for x, y in zip(X, Y):
                mask = self.mask_image.read_region((x, y), 0, (PATCH_SIZE, PATCH_SIZE))
                mask_gt = np.array(mask)
                mask_gt = cv2.cvtColor(mask_gt, cv2.COLOR_BGR2GRAY)

                white_pixel_cnt_gt = cv2.countNonZero(mask_gt)

                if white_pixel_cnt_gt > ((PATCH_SIZE * PATCH_SIZE) * 0.90):
                    # mask = Image.fromarray(mask)
                    patch = self.wsi_image.read_region((x, y), 0, (PATCH_SIZE, PATCH_SIZE))
                    patch.save(PROCESSED_PATCHES_FROM_USE_MASK_POSITIVE_PATH + PATCH_TUMOR_PREFIX +
                               str(self.positive_patch_index), 'PNG')
                    self.positive_patch_index += 1
                    patch.close()

                mask.close()

    def extract_patches_normal(self, bounding_boxes):
        """
            Extract negative patches from Normal WSIs

            Save extracted patches to desk as .png image files

            :param bounding_boxes: list of bounding boxes corresponds to detected ROIs
            :return:

        """
        mag_factor = pow(2, self.level_used)

        print('No. of ROIs to extract patches from: %d' % len(bounding_boxes))

        for i, bounding_box in enumerate(bounding_boxes):
            b_x_start = int(bounding_box[0]) * mag_factor
            b_y_start = int(bounding_box[1]) * mag_factor
            b_x_end = (int(bounding_box[0]) + int(bounding_box[2])) * mag_factor
            b_y_end = (int(bounding_box[1]) + int(bounding_box[3])) * mag_factor
            X = np.random.random_integers(b_x_start, high=b_x_end, size=500)
            Y = np.random.random_integers(b_y_start, high=b_y_end, size=500)
            # X = np.arange(b_x_start, b_x_end-256, 5)
            # Y = np.arange(b_y_start, b_y_end-256, 5)

            for x, y in zip(X, Y):
                patch = self.wsi_image.read_region((x, y), 0, (PATCH_SIZE, PATCH_SIZE))
                patch_array = np.array(patch)

                patch_hsv = cv2.cvtColor(patch_array, cv2.COLOR_BGR2HSV)
                # [20, 20, 20]
                lower_red = np.array([20, 20, 20])
                # [255, 255, 255]
                upper_red = np.array([200, 200, 200])
                mask = cv2.inRange(patch_hsv, lower_red, upper_red)
                white_pixel_cnt = cv2.countNonZero(mask)

                if white_pixel_cnt > ((PATCH_SIZE * PATCH_SIZE) * 0.50):
                    # mask = Image.fromarray(mask)
                    patch.save(PROCESSED_PATCHES_NORMAL_NEGATIVE_PATH + PATCH_NORMAL_PREFIX +
                               str(self.negative_patch_index), 'PNG')
                    # mask.save(PROCESSED_PATCHES_NORMAL_PATH + PATCH_NORMAL_PREFIX + str(self.patch_index),
                    #           'PNG')
                    self.negative_patch_index += 1

                patch.close()

    def extract_patches_tumor(self, bounding_boxes):
        """
            Extract both, negative patches from Normal area and positive patches from Tumor area

            Save extracted patches to desk as .png image files

            :param bounding_boxes: list of bounding boxes corresponds to detected ROIs
            :return:
            
        """
        mag_factor = pow(2, self.level_used)

        print('No. of ROIs to extract patches from: %d' % len(bounding_boxes))

        for i, bounding_box in enumerate(bounding_boxes):
            b_x_start = int(bounding_box[0]) * mag_factor
            b_y_start = int(bounding_box[1]) * mag_factor
            b_x_end = (int(bounding_box[0]) + int(bounding_box[2])) * mag_factor
            b_y_end = (int(bounding_box[1]) + int(bounding_box[3])) * mag_factor
            X = np.random.random_integers(b_x_start, high=b_x_end, size=500)
            Y = np.random.random_integers(b_y_start, high=b_y_end, size=500)
            # X = np.arange(b_x_start, b_x_end-256, 5)
            # Y = np.arange(b_y_start, b_y_end-256, 5)

            for x, y in zip(X, Y):
                patch = self.wsi_image.read_region((x, y), 0, (PATCH_SIZE, PATCH_SIZE))
                mask = self.mask_image.read_region((x, y), 0, (PATCH_SIZE, PATCH_SIZE))
                mask_gt = np.array(mask)
                # mask_gt = cv2.cvtColor(mask_gt, cv2.COLOR_BGR2GRAY)
                mask_gt = cv2.cvtColor(mask_gt, cv2.COLOR_BGR2GRAY)
                patch_array = np.array(patch)

                white_pixel_cnt_gt = cv2.countNonZero(mask_gt)

                if white_pixel_cnt_gt == 0:  # mask_gt does not contain tumor area
                    patch_hsv = cv2.cvtColor(patch_array, cv2.COLOR_BGR2HSV)
                    lower_red = np.array([20, 20, 20])
                    upper_red = np.array([200, 200, 200])
                    mask_patch = cv2.inRange(patch_hsv, lower_red, upper_red)
                    white_pixel_cnt = cv2.countNonZero(mask_patch)

                    if white_pixel_cnt > ((PATCH_SIZE * PATCH_SIZE) * 0.50):
                        # mask = Image.fromarray(mask)
                        patch.save(PROCESSED_PATCHES_TUMOR_NEGATIVE_PATH + PATCH_NORMAL_PREFIX +
                                   str(self.negative_patch_index), 'PNG')
                        # mask.save(PROCESSED_PATCHES_NORMAL_PATH + PATCH_NORMAL_PREFIX + str(self.patch_index),
                        #           'PNG')
                        self.negative_patch_index += 1
                else:  # mask_gt contains tumor area
                    if white_pixel_cnt_gt >= ((PATCH_SIZE * PATCH_SIZE) * 0.85):
                        patch.save(PROCESSED_PATCHES_POSITIVE_PATH + PATCH_TUMOR_PREFIX +
                                   str(self.positive_patch_index), 'PNG')
                        self.positive_patch_index += 1

                patch.close()
                mask.close()

    def read_wsi_mask(self, wsi_path, mask_path):
        try:
            self.cur_wsi_path = wsi_path
            self.wsi_image = OpenSlide(wsi_path)
            self.mask_image = OpenSlide(mask_path)

            self.level_used = min(self.def_level, self.wsi_image.level_count - 1, self.mask_image.level_count - 1)

            self.mask_pil = self.mask_image.read_region((0, 0), self.level_used,
                                                            self.mask_image.level_dimensions[self.level_used])
            self.mask = np.array(self.mask_pil)

        except OpenSlideUnsupportedFormatError:
            print('Exception: OpenSlideUnsupportedFormatError')
            return False

        return True

    def read_wsi_normal(self, wsi_path):
        """
            # =====================================================================================
            # read WSI image and resize
            # Due to memory constraint, we use down sampled (4th level, 1/32 resolution) image
            # ======================================================================================
        """
        try:
            self.cur_wsi_path = wsi_path
            self.wsi_image = OpenSlide(wsi_path)
            self.level_used = min(self.def_level, self.wsi_image.level_count - 1)

            self.rgb_image_pil = self.wsi_image.read_region((0, 0), self.level_used,
                                                            self.wsi_image.level_dimensions[self.level_used])
            self.rgb_image = np.array(self.rgb_image_pil)

        except OpenSlideUnsupportedFormatError:
            print('Exception: OpenSlideUnsupportedFormatError')
            return False

        return True

    def read_wsi_tumor(self, wsi_path, mask_path):
        """
            # =====================================================================================
            # read WSI image and resize
            # Due to memory constraint, we use down sampled (4th level, 1/32 resolution) image
            # ======================================================================================
        """
        try:
            self.cur_wsi_path = wsi_path
            self.wsi_image = OpenSlide(wsi_path)
            self.mask_image = OpenSlide(mask_path)

            self.level_used = min(self.def_level, self.wsi_image.level_count - 1, self.mask_image.level_count - 1)

            self.rgb_image_pil = self.wsi_image.read_region((0, 0), self.level_used,
                                                            self.wsi_image.level_dimensions[self.level_used])
            self.rgb_image = np.array(self.rgb_image_pil)

        except OpenSlideUnsupportedFormatError:
            print('Exception: OpenSlideUnsupportedFormatError')
            return False

        return True

    def find_roi_n_extract_patches_mask(self):
        mask = cv2.cvtColor(self.mask, cv2.COLOR_BGR2GRAY)
        contour_mask, bounding_boxes = self.get_image_contours_mask(np.array(mask), np.array(self.mask))

        # contour_mask = cv2.resize(contour_mask, (0, 0), fx=0.40, fy=0.40)
        # cv2.imshow('contour_mask', np.array(contour_mask))
        self.mask_pil.close()
        self.extract_patches_mask(bounding_boxes)
        self.wsi_image.close()
        self.mask_image.close()

    def find_roi_n_extract_patches_normal(self):
        hsv = cv2.cvtColor(self.rgb_image, cv2.COLOR_BGR2HSV)
        # [20, 20, 20]
        lower_red = np.array([20, 50, 20])
        # [255, 255, 255]
        upper_red = np.array([200, 150, 200])
        mask = cv2.inRange(hsv, lower_red, upper_red)

        # (50, 50)
        close_kernel = np.ones((25, 25), dtype=np.uint8)
        image_close = Image.fromarray(cv2.morphologyEx(np.array(mask), cv2.MORPH_CLOSE, close_kernel))
        # (30, 30)
        open_kernel = np.ones((30, 30), dtype=np.uint8)
        image_open = Image.fromarray(cv2.morphologyEx(np.array(image_close), cv2.MORPH_OPEN, open_kernel))
        contour_rgb, bounding_boxes = self.get_image_contours_normal(np.array(image_open), self.rgb_image)

        # contour_rgb = cv2.resize(contour_rgb, (0, 0), fx=0.40, fy=0.40)
        # cv2.imshow('contour_rgb', np.array(contour_rgb))
        self.rgb_image_pil.close()
        self.extract_patches_normal(bounding_boxes)
        self.wsi_image.close()

    def find_roi_n_extract_patches_tumor(self):
        hsv = cv2.cvtColor(self.rgb_image, cv2.COLOR_BGR2HSV)
        lower_red = np.array([20, 20, 20])
        upper_red = np.array([255, 255, 255])
        mask = cv2.inRange(hsv, lower_red, upper_red)

        # (50, 50)
        close_kernel = np.ones((50, 50), dtype=np.uint8)
        image_close = Image.fromarray(cv2.morphologyEx(np.array(mask), cv2.MORPH_CLOSE, close_kernel))
        # (30, 30)
        open_kernel = np.ones((30, 30), dtype=np.uint8)
        image_open = Image.fromarray(cv2.morphologyEx(np.array(image_close), cv2.MORPH_OPEN, open_kernel))
        contour_rgb, bounding_boxes = self.get_image_contours_tumor(np.array(image_open), self.rgb_image)

        # contour_rgb = cv2.resize(contour_rgb, (0, 0), fx=0.40, fy=0.40)
        # cv2.imshow('contour_rgb', np.array(contour_rgb))
        self.rgb_image_pil.close()
        self.extract_patches_tumor(bounding_boxes)
        self.wsi_image.close()
        self.mask_image.close()

    @staticmethod
    def get_image_contours_mask(cont_img, mask_img):
        _, contours, _ = cv2.findContours(cont_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        bounding_boxes = [cv2.boundingRect(c) for c in contours]
        contours_mask_image_array = np.array(mask_img)
        line_color = (255, 0, 0)  # blue color code
        cv2.drawContours(contours_mask_image_array, contours, -1, line_color, 1)
        return contours_mask_image_array, bounding_boxes

    @staticmethod
    def get_image_contours_normal(cont_img, rgb_image):
        _, contours, _ = cv2.findContours(cont_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        bounding_boxes = [cv2.boundingRect(c) for c in contours]
        contours_rgb_image_array = np.array(rgb_image)
        line_color = (255, 0, 0)  # blue color code
        cv2.drawContours(contours_rgb_image_array, contours, -1, line_color, 3)
        return contours_rgb_image_array, bounding_boxes

    @staticmethod
    def get_image_contours_tumor(cont_img, rgb_image):
        _, contours, _ = cv2.findContours(cont_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        bounding_boxes = [cv2.boundingRect(c) for c in contours]
        contours_rgb_image_array = np.array(rgb_image)

        line_color = (255, 0, 0)  # blue color code
        cv2.drawContours(contours_rgb_image_array, contours, -1, line_color, 3)
        # cv2.drawContours(mask_image, contours_mask, -1, line_color, 3)
        return contours_rgb_image_array, bounding_boxes

    def wait(self):
        self.key = cv2.waitKey(0) & 0xFF
        print('key: %d' % self.key)

        if self.key == 27:  # escape
            return False
        elif self.key == 81:  # <- (prev)
            self.index -= 1
            if self.index < 0:
                self.index = len(self.wsi_paths) - 1
        elif self.key == 83:  # -> (next)
            self.index += 1
            if self.index >= len(self.wsi_paths):
                self.index = 0

        return True
예제 #28
0
            r.raise_for_status()
            for buf in r.iter_content(10 << 20):
                if not buf:
                    break
                fh.write(buf)
                hash.update(buf)
                count += len(buf)
        if count != int(r.headers['Content-Length']):
            raise IOError('Short read fetching %s' % slide_relpath)
        if hash.hexdigest() != slide_info['sha256']:
            raise IOError('Hash mismatch fetching %s' % slide_relpath)

        # Open slide
        slide = None
        try:
            slide = OpenSlide(slide_path)
        except OpenSlideError:
            if urlpath.splitext(slide_relpath)[1] == '.zip':
                # Unzip slide
                print 'Extracting %s...' % slide_relpath
                temp_path = mkdtemp(dir=tempdir)
                with ZipFile(slide_path) as zf:
                    zf.extractall(path=temp_path)
                # Find slide in zip
                for sub_name in os.listdir(temp_path):
                    try:
                        slide_path = os.path.join(temp_path, sub_name)
                        slide = OpenSlide(slide_path)
                    except OpenSlideError:
                        pass
                    else:
예제 #29
0
 def setUp(self):
     self.osr = OpenSlide(file_path(self.FILENAME))
    os.makedirs('../Neutrophil/Tiles_final/pos')

if not os.path.exists('../Neutrophil/Tiles_final/neg'):
    os.makedirs('../Neutrophil/Tiles_final/neg')

coords = pd.read_excel('../Neutrophil/all_features_circa_July.xlsx', header=0)
sample = coords.loc[(coords['Slide'] == 'Slide80.scn')]
sample = sample.loc[(coords['Review'] == '+') | (coords['Review'] == '-')]
sample = sample.sample(frac=1).reset_index(drop=True)
pos = coords.loc[(coords['Review'] == '+')
                 & (coords['Slide'] == 'Slide80.scn')]

sample.to_csv('../Neutrophil/Tiles_final/sample.csv', header=0, index=False)
pos.to_csv('../Neutrophil/Tiles_final/pos.csv', header=0, index=False)

slide = OpenSlide(
    "../Neutrophil/ImageCollection_0000026280_2016-10-27 14_13_01.scn")

assert 'openslide.bounds-height' in slide.properties
assert 'openslide.bounds-width' in slide.properties
assert 'openslide.bounds-x' in slide.properties
assert 'openslide.bounds-y' in slide.properties

xo = int(slide.properties['openslide.bounds-x'])
yo = int(slide.properties['openslide.bounds-y'])
bounds_height = int(slide.properties['openslide.bounds-height'])
bounds_width = int(slide.properties['openslide.bounds-width'])

sample.loc[:, 'X'] = sample.loc[:, 'X'] + xo
sample.loc[:, 'Y'] = sample.loc[:, 'Y'] + yo
pos.loc[:, 'X'] = pos.loc[:, 'X'] + xo
pos.loc[:, 'Y'] = pos.loc[:, 'Y'] + yo
예제 #31
0
class OpenSlideStore(Mapping):
    """Wraps an OpenSlide object as a multiscale Zarr Store.

    Parameters
    ----------
    path: str
        The file to open with OpenSlide.
    tilesize: int
        Desired "chunk" size for zarr store.
    """
    def __init__(self, path: str, tilesize: int = 512):
        self._slide = OpenSlide(path)
        self._tilesize = tilesize
        self._store = create_meta_store(self._slide, tilesize)

    def __getitem__(self, key: str):
        if key in self._store:
            # key is for metadata
            return self._store[key]

        # key should now be a path to an array chunk
        # e.g '3/4.5.0' -> '<level>/<chunk_key>'
        try:
            x, y, level = _parse_chunk_path(key)
            location = self._ref_pos(x, y, level)
            size = (self._tilesize, self._tilesize)
            tile = self._slide.read_region(location, level, size)
        except ArgumentError as err:
            # Can occur if trying to read a closed slide
            raise err
        except:
            # TODO: probably need better error handling.
            # If anything goes wrong, we just signal the chunk
            # is missing from the store.
            raise KeyError(key)

        return np.array(tile).tobytes()

    def __contains__(self, key: str):
        return key in self._store

    def __eq__(self, other):
        return (isinstance(other, OpenSlideStore)
                and self._slide._filename == other._slide._filename)

    def __iter__(self):
        return iter(self.keys())

    def __len__(self):
        return sum(1 for _ in self)

    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.close()

    def _ref_pos(self, x: int, y: int, level: int):
        dsample = self._slide.level_downsamples[level]
        xref = int(x * dsample * self._tilesize)
        yref = int(y * dsample * self._tilesize)
        return xref, yref

    def keys(self):
        return self._store.keys()

    def close(self):
        self._slide.close()
예제 #32
0
def read_openslide_tile(slide: openslide.OpenSlide, downsample, tile_rect):
    level = slide.get_best_level_for_downsample(downsample)
    tile = slide.read_region((tile_rect[0], tile_rect[1]), level, (tile_rect[2], tile_rect[3]))
    return tile
예제 #33
0
def run(file_path, location_path, level, padding, camel_17):
    slide = OpenSlide(file_path)

    print('==> making contours of tissue region..')

    ### Pad with 255
    if padding == True:
        x_lv_, y_lv_ = 0, 0
        w_lv_, h_lv_ = slide.level_dimensions[level]

        wsi_pil_lv_ = slide.read_region((0,0), level,\
            (w_lv_, h_lv_))

        wsi_ary_lv_ = np.array(wsi_pil_lv_)
        wsi_bgr_lv_ = cv2.cvtColor(wsi_ary_lv_, cv2.COLOR_RGBA2BGR)

        margin_top = int(round(h_lv_ / 12.))
        margin_bottom = int(round(h_lv_ / 32.))
        wsi_bgr_lv_[0:margin_top, :] = 255
        wsi_bgr_lv_[h_lv_ - margin_bottom:h_lv_, :] = 255

    else:
        wsi_pil_lv_ = slide.read_region((0, 0), level,\
                slide.level_dimensions[level])
        wsi_ary_lv_ = np.array(wsi_pil_lv_)
        wsi_bgr_lv_ = cv2.cvtColor(wsi_ary_lv_, cv2.COLOR_RGBA2BGR)

    if camel_17:
        wsi_bgr_lv_black = (wsi_bgr_lv_ == 0)
        wsi_bgr_lv_[wsi_bgr_lv_black] = 255

### Remove black region.
    """
    wsi_bgr_lv_sum = np.sum(wsi_bgr_lv_, 2)
    wsi_criterion = (wsi_bgr_lv_sum / 3) < 38
    wsi_bgr_lv_[wsi_criterion] = np.array([255, 255, 255])
    """

    ### Visualizing
    #    origin = wsi_bgr_lv_.copy()
    #    plt.subplot(1, 2, 1), plt.imshow(origin)
    #    plt.title("origin"), plt.xticks([]), plt.yticks([])
    #    plt.subplot(1, 2, 2), plt.imshow(wsi_bgr_lv_4 )
    #    plt.title("after"), plt.xticks([]), plt.yticks([])
    #    plt.show()
    #    exit()

    wsi_gray_lv_ = cv2.cvtColor(wsi_bgr_lv_, cv2.COLOR_BGR2GRAY)

    #    ret, wsi_bin_0255_lv_4 = cv2.threshold( \
    #                          wsi_gray_lv_4, \
    #                          127, 255, \
    #                          cv2.THRESH_BINARY )

    ### Visualizing
    #    plt.subplot(1, 2, 1), plt.imshow(wsi_bgr_lv_4 )
    #    plt.title("bgr"), plt.xticks([]), plt.yticks([])
    #    plt.subplot(1, 2, 2), plt.imshow(wsi_gray_lv_4, 'gray')
    #    plt.title("gray"), plt.xticks([]), plt.yticks([])
    #    plt.show()
    #    exit()

    #    blur_lv_ = cv2.GaussianBlur(wsi_gray_lv_, (5, 5), 0)
    ret, wsi_bin_0255_lv_ = cv2.threshold( \
                    wsi_gray_lv_, 0, 255, \
                    cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

    ### Visualizing
    #    plt.subplot(1, 2, 1), plt.imshow(wsi_bgr_lv_4 )
    #    plt.title("bgr"), plt.xticks([]), plt.yticks([])
    #    plt.subplot(1, 2, 2), plt.imshow(wsi_bin_0255_lv_4, 'gray')
    #    plt.title("gray"), plt.xticks([]), plt.yticks([])
    #    plt.show()
    #    exit()

    ### Morphology

    kernel_o = np.ones((2, 2), dtype=np.uint8)
    kernel_c = np.ones((4, 4), dtype=np.uint8)
    wsi_bin_0255_lv_ = cv2.morphologyEx( \
            wsi_bin_0255_lv_, \
            cv2.MORPH_CLOSE, \
            kernel_c)
    wsi_bin_0255_lv_ = cv2.morphologyEx( \
            wsi_bin_0255_lv_, \
            cv2.MORPH_OPEN, \
            kernel_o)

    _, contours_tissue_lv_, hierarchy = \
            cv2.findContours(\
                    wsi_bin_0255_lv_, \
                    cv2.RETR_TREE, \
                    cv2.CHAIN_APPROX_SIMPLE)

    print('==> making tissue mask..')

    mask_shape_lv_ = wsi_gray_lv_.shape
    tissue_mask_lv_ = make_mask(mask_shape_lv_, contours_tissue_lv_)

    print('==> saving slide_lv_' + str(level) + ' at ' + location_path)
    cv2.imwrite(location_path, tissue_mask_lv_)
예제 #34
0
    def fetch_patches_from_slide(self,
                                 wsi_filepath,
                                 count,
                                 src_size=512,
                                 patch_size=512,
                                 tissue_threshold=0.8,
                                 blur=0,
                                 he_augmentation=False,
                                 rotations=None):
        slide = OpenSlide(wsi_filepath)

        # load image with lower resolution
        desirable_long_edge = 2000

        level_downsample = 0
        for i, (w, h) in enumerate(slide.level_dimensions):
            if abs(max(w, h) - desirable_long_edge) < \
                    abs(max(slide.level_dimensions[level_downsample]) - desirable_long_edge):
                level_downsample = i
        magnification = slide.level_downsamples[level_downsample]
        image_downsample = slide.read_region(
            (0, 0), level_downsample,
            (slide.level_dimensions[level_downsample]))

        # Otsu binarization

        # set transparent region to white
        alpha = np.asarray(image_downsample, dtype=np.uint8)[:, :, 3]

        src = np.average(np.asarray(image_downsample,
                                    dtype=np.uint8)[:, :, :3],
                         axis=2)
        src[alpha == 0] = 255
        src = 255 - cv2.convertScaleAbs(src)
        th, binarized = cv2.threshold(src, 0, 255,
                                      cv2.THRESH_BINARY + cv2.THRESH_OTSU)

        # dilation
        kernel = np.ones((2, 2), np.uint8)
        dilated = cv2.dilate(binarized, kernel, iterations=1)

        ret_images = []
        src_downsampled_size = 512 / magnification
        padding = int(src_size / 2**0.5 / magnification) + 10
        for i in range(count):
            # select region to crop using tissue binary map
            while True:
                cx = random.randint(
                    padding,
                    slide.level_dimensions[level_downsample][0] - padding)
                cy = random.randint(
                    padding,
                    slide.level_dimensions[level_downsample][1] - padding)
                angle = random.random() * 2 * math.pi

                # crop
                crop_size = int(
                    src_downsampled_size * 2**0.5 *
                    max(abs(math.cos(angle)), abs(math.sin(angle))))
                cropped = dilated[int(cy - crop_size / 2):int(cy +
                                                              crop_size / 2),
                                  int(cx - crop_size / 2):int(cx +
                                                              crop_size / 2)]
                mat = cv2.getRotationMatrix2D((crop_size / 2, crop_size / 2),
                                              45 + 360 * angle / (2 * math.pi),
                                              1)
                rotated = cv2.warpAffine(cropped, mat, (crop_size, crop_size))

                result = rotated[
                         int(crop_size / 2 - src_downsampled_size / 2):int(crop_size / 2 + src_downsampled_size / 2), \
                         int(crop_size / 2 - src_downsampled_size / 2):int(crop_size / 2 + src_downsampled_size / 2)]
                if np.average(result) / 255 > tissue_threshold:
                    break

            # transform to raw scale
            cx = cx * magnification
            cy = cy * magnification

            # real cropping
            angles = [angle]
            if rotations is not None:
                for rot in rotations:
                    angles.append(angle + rot / 180 * math.pi)

            def crop(angle):
                crop_size = int(
                    src_size * 2**0.5 *
                    max(abs(math.cos(angle)), abs(math.sin(angle))))
                cropped = np.asarray(slide.read_region(
                    (int(cx - crop_size / 2), int(cy - crop_size / 2)), 0,
                    (crop_size, crop_size)),
                                     dtype=np.float32)[:, :, :3]
                mat = cv2.getRotationMatrix2D((crop_size / 2, crop_size / 2),
                                              45 + 360 * angle / (2 * math.pi),
                                              1)
                rotated = cv2.warpAffine(cropped, mat, (crop_size, crop_size))

                result = rotated[int(crop_size / 2 - src_size / 2):int(crop_size / 2 + src_size / 2), \
                         int(crop_size / 2 - src_size / 2):int(crop_size / 2 + src_size / 2)]
                result = cv2.resize(result,
                                    (patch_size, patch_size)).transpose(
                                        (2, 0, 1)) / 255
                return result

            results = [crop(angle) for angle in angles]

            # color matching
            if self.use_color_matching:
                results = [
                    self.match_color(result.transpose(1, 2,
                                                      0)).transpose(2, 0, 1)
                    for result in results
                ]

            # blurring effect
            if blur > 0:
                blur_size = random.randint(1, blur)
                results = [
                    cv2.blur(result.transpose(1, 2, 0),
                             (blur_size, blur_size)).transpose((2, 0, 1))
                    for result in results
                ]

            if he_augmentation:

                def he_aug(result):
                    hed = rgb2hed(np.clip(result.transpose(1, 2, 0), -1.0,
                                          1.0))
                    ah = 0.95 + random.random() * 0.1
                    bh = -0.05 + random.random() * 0.1
                    ae = 0.95 + random.random() * 0.1
                    be = -0.05 + random.random() * 0.1
                    hed[:, :, 0] = ah * hed[:, :, 0] + bh
                    hed[:, :, 1] = ae * hed[:, :, 1] + be
                    result = hed2rgb(hed).transpose(2, 0, 1)
                    return result

                results = [he_aug(result) for result in results]

            if rotations is None:
                ret_images.append(np.clip(results[0], 1e-7, 1.0 - 1e-7))
            else:
                results = [
                    np.clip(result, 1e-7, 1.0 - 1e-7) for result in results
                ]
                ret_images.append(tuple(results))

        return ret_images
예제 #35
0
def extract_features_test(heatmap_prob_name_postfix_first_model,
                          heatmap_prob_name_postfix_second_model, f_test):
    print(
        '************************** extract_features_test() ***************************'
    )
    print('heatmap_prob_name_postfix_first_model: %s' %
          heatmap_prob_name_postfix_first_model)
    print('heatmap_prob_name_postfix_second_model: %s' %
          heatmap_prob_name_postfix_second_model)
    print('f_test: %s' % f_test)

    test_wsi_paths = glob.glob(
        os.path.join(
            '/media/jiaojiao/Seagate Backup Plus Drive1/CAMELYON16/TrainingData/Train_Tumor',
            '*.tif'))
    #test_wsi_paths = glob.glob(os.path.join(utils.TUMOR_WSI_PATH, '*.tif'))
    test_wsi_paths.sort()
    features_file_test = open(f_test, 'w')

    wr_test = csv.writer(features_file_test, quoting=csv.QUOTE_NONNUMERIC)
    wr_test.writerow(
        utils.heatmap_feature_names[:len(utils.heatmap_feature_names) - 1])
    for wsi_path in test_wsi_paths:
        wsi_name = utils.get_filename_from_path(wsi_path)
        level_used = OpenSlide(
            os.path.join(
                '/media/jiaojiao/Seagate Backup Plus Drive1/CAMELYON16/TrainingData/Train_Tumor',
                wsi_path)).level_count - 1
        if level_used > 8:
            level_used = 8
        print('extracting features for: %s' % wsi_name)
        heatmap_prob_path = glob.glob(
            os.path.join(
                utils.HEAT_MAP_DIR,
                '*%s*%s' % (wsi_name, heatmap_prob_name_postfix_first_model)))
        # print(heatmap_prob_path)
        image_open = wsi_ops.get_image_open(wsi_path)
        heatmap_prob = cv2.imread(heatmap_prob_path[0])

        if heatmap_prob_name_postfix_second_model is not None:
            heatmap_prob_path_second_model = glob.glob(
                os.path.join(
                    utils.HEAT_MAP_DIR, '*%s*%s' %
                    (wsi_name, heatmap_prob_name_postfix_second_model)))
            heatmap_prob_second_model = cv2.imread(
                heatmap_prob_path_second_model[0])

            for row in range(heatmap_prob.shape[0]):
                for col in range(heatmap_prob.shape[1]):
                    if heatmap_prob[
                            row, col,
                            0] >= 0.90 * 255 and heatmap_prob_second_model[
                                row, col, 0] < 0.50 * 255:
                        heatmap_prob[row, col, :] = heatmap_prob_second_model[
                            row, col, :]

        features = extract_features(heatmap_prob, image_open)
        print(features)
        wr_test.writerow(features)
        csv_name = wsi_name[0:9] + '.csv'
        csv_path = os.path.join(utils.results, csv_name)
        csv_file = open(csv_path, 'w')
        csv_test = csv.writer(csv_file, quoting=csv.QUOTE_NONNUMERIC)
        get_result(heatmap_prob, csv_test, level_used)
예제 #36
0
class NDPI_Slide:
    def __init__(self, ndpi_path):
        self.ndpi_slide = OpenSlide(ndpi_path)

    def read_image(self, level_select):
        """
        Read the whole image at the selected level
        :param level_select:
        :return:
        """
        level_count = self.ndpi_slide.level_count
        level_dims = self.ndpi_slide.level_dimensions

        # for level in range(level_count):
        #     print("level: {} \t dim: {}".format(level, level_dims[level]))

        im_low_res = self.ndpi_slide.read_region(location=(0, 0),
                                                 level=level_select,
                                                 size=level_dims[level_select])

        im_low_res = np.array(im_low_res)
        if im_low_res.shape[2] > 3:
            im_low_res = im_low_res[:, :, 0:3]

        return im_low_res

    def read_region(self, location, level, size):
        """
        Read image region
        :param location: (x, y)
        :param level:
        :param size: (w, h)
        :return:
        """
        image = self.ndpi_slide.read_region(location, level, size)
        image = np.array(image)
        if image.shape[2] > 3:
            image = image[:, :, 0:3]  # convert from RGBA to RGB
        return image

    def read_ndpa_annotation(self, ndpa_path):

        mmp_x = float(
            self.ndpi_slide.properties['openslide.mpp-x'])  # pixel size in um
        mmp_y = float(
            self.ndpi_slide.properties['openslide.mpp-y'])  # pixel size in um

        # Distance in X from the center of the entire slide (i.e., the macro image) to the center of the main image, in nm
        offset_x = float(
            self.ndpi_slide.properties['hamamatsu.XOffsetFromSlideCentre'])
        # Distance in Y from the center of the entire slide to the center of the main image, in nm
        offset_y = float(
            self.ndpi_slide.properties['hamamatsu.YOffsetFromSlideCentre'])
        level_0_dim = self.ndpi_slide.level_dimensions[0]
        level_0_width = level_0_dim[0]
        level_0_height = level_0_dim[1]

        # Steps to convert from NDPA coordinates to pixel coordinates
        # 0. The point coordinates are in physical units, relative to the center of the entire slide
        # 1. Subtract the [XY]OffsetFromSlideCentre ==> physical units, relative to the center of the main image
        # 2. Divide by (mpp-[xy] * 1000) ==> pixel coordinates, relative to the center of the main image
        # 3. Subtract (level-0 dimensions / 2) ==> level 0 pixel coordinates
        root = ET.parse(ndpa_path).getroot()
        polygons = []
        rects = []
        titles = []
        for ndpviewstate_node in root.findall('ndpviewstate'):
            titles.append(ndpviewstate_node.find('title').text)
            annotation_node = ndpviewstate_node.find('annotation')
            pointlist_node = annotation_node.find('pointlist')
            points = []
            for point_node in pointlist_node.findall('point'):
                x, y = float(point_node.find('x').text), float(
                    point_node.find('y').text)  # physical position
                x, y = x - offset_x, y - offset_y  # physical position with respect to image center
                x, y = x / (mmp_x * 1000), y / (
                    mmp_y * 1000
                )  # pixel position with respect to image center
                x, y = x + level_0_width / 2, y + level_0_height / 2  # pixel position with respect to image origin
                points.append((int(x), int(y)))

            points = np.array(points)
            rect = cv2.boundingRect(points)
            polygons.append(points)
            rects.append(rect)

        return polygons, rects, titles
예제 #37
0
class Opener:
    def __init__(self, path):
        self.warning = ''
        self.path = path
        self.reader = None
        self.tilesize = 1024
        self.ext = check_ext(path)
        self.default_dtype = np.uint16

        if self.ext == '.ome.tif' or self.ext == '.ome.tiff':
            self.io = TiffFile(self.path, is_ome=False)
            self.group = zarr.open(self.io.series[0].aszarr())
            self.reader = 'tifffile'
            self.ome_version = self._get_ome_version()
            print("OME ", self.ome_version)
            num_channels = self.get_shape()[0]
            tile_0 = self.get_tifffile_tile(num_channels, 0, 0, 0, 0, 1024)
            if tile_0 is not None:
                self.default_dtype = tile_0.dtype

            if (num_channels == 3 and tile_0.dtype == 'uint8'):
                self.rgba = True
                self.rgba_type = '3 channel'
            elif (num_channels == 1 and tile_0.dtype == 'uint8'):
                self.rgba = True
                self.rgba_type = '1 channel'
            else:
                self.rgba = False
                self.rgba_type = None

            print("RGB ", self.rgba)
            print("RGB type ", self.rgba_type)

        elif self.ext == '.svs':
            self.io = OpenSlide(self.path)
            self.dz = DeepZoomGenerator(self.io,
                                        tile_size=1024,
                                        overlap=0,
                                        limit_bounds=True)
            self.reader = 'openslide'
            self.rgba = True
            self.rgba_type = None
            self.default_dtype = np.uint8

            print("RGB ", self.rgba)
            print("RGB type ", self.rgba_type)

        else:
            self.reader = None

    def _get_ome_version(self):
        try:
            software = self.io.pages[0].tags[305].value
            sub_ifds = self.io.pages[0].tags[330].value
            if "Faas" in software or sub_ifds is None:
                return 5

            m = re.search('OME\\sBio-Formats\\s(\\d+)\\.\\d+\\.\\d+', software)
            if m is None:
                return 5
            return int(m.group(1))
        except Exception as e:
            print(e)
            return 5

    def load_xml_markers(self):
        if self.ext == '.ome.tif' or self.ext == '.ome.tiff':
            try:
                metadata = ome_types.from_tiff(self.path)
            except Exception as e:
                return []

            if not metadata or not metadata.images or not metadata.images[0]:
                return []

            metadata_pixels = metadata.images[0].pixels
            if not metadata_pixels or not metadata_pixels.channels:
                return []

            return [c.name for c in metadata_pixels.channels]
        else:
            return []

    def close(self):
        self.io.close()

    def is_rgba(self, rgba_type=None):
        if rgba_type is None:
            return self.rgba
        else:
            return self.rgba and rgba_type == self.rgba_type

    def get_level_tiles(self, level, tile_size):
        if self.reader == 'tifffile':

            # Negative indexing to support shape len 3 or len 2
            ny = int(np.ceil(self.group[level].shape[-2] / tile_size))
            nx = int(np.ceil(self.group[level].shape[-1] / tile_size))
            return (nx, ny)
        elif self.reader == 'openslide':
            l = self.dz.level_count - 1 - level
            return self.dz.level_tiles[l]

    def get_shape(self):
        def parse_shape(shape):
            if len(shape) >= 3:
                (num_channels, shape_y, shape_x) = shape[-3:]
            else:
                (shape_y, shape_x) = shape
                num_channels = 1

            return (num_channels, shape_x, shape_y)

        if self.reader == 'tifffile':

            (num_channels, shape_x, shape_y) = parse_shape(self.group[0].shape)
            all_levels = [parse_shape(v.shape) for v in self.group.values()]
            num_levels = len(
                [shape for shape in all_levels if max(shape[1:]) > 512])
            return (num_channels, num_levels, shape_x, shape_y)

        elif self.reader == 'openslide':

            (width, height) = self.io.dimensions

            def has_one_tile(counts):
                return max(counts) == 1

            small_levels = list(filter(has_one_tile, self.dz.level_tiles))
            level_count = self.dz.level_count - len(small_levels) + 1

            return (3, level_count, width, height)

    def read_tiles(self, level, channel_number, tx, ty, tilesize):
        ix = tx * tilesize
        iy = ty * tilesize

        num_channels = self.get_shape()[0]
        try:
            if num_channels == 1:
                tile = self.group[level][iy:iy + tilesize, ix:ix + tilesize]
            else:
                tile = self.group[level][channel_number, iy:iy + tilesize,
                                         ix:ix + tilesize]
            tile = np.squeeze(tile)
            return tile
        except Exception as e:
            G['logger'].error(e)
            return None

    def get_tifffile_tile(self,
                          num_channels,
                          level,
                          tx,
                          ty,
                          channel_number,
                          tilesize=1024):

        if self.reader == 'tifffile':

            tile = self.read_tiles(level, channel_number, tx, ty, tilesize)

            if tile is None:
                return np.zeros((tilesize, tilesize), dtype=self.default_dtype)

            return tile

    def get_tile(self, num_channels, level, tx, ty, channel_number, fmt=None):

        if self.reader == 'tifffile':

            if self.is_rgba('3 channel'):
                tile_0 = self.get_tifffile_tile(num_channels, level, tx, ty, 0,
                                                1024)
                tile_1 = self.get_tifffile_tile(num_channels, level, tx, ty, 1,
                                                1024)
                tile_2 = self.get_tifffile_tile(num_channels, level, tx, ty, 2,
                                                1024)
                tile = np.zeros((tile_0.shape[0], tile_0.shape[1], 3),
                                dtype=np.uint8)
                tile[:, :, 0] = tile_0
                tile[:, :, 1] = tile_1
                tile[:, :, 2] = tile_2
                _format = 'I;8'
            else:
                tile = self.get_tifffile_tile(num_channels, level, tx, ty,
                                              channel_number, 1024)
                _format = fmt if fmt else 'I;16'

                if (_format == 'RGBA' and tile.dtype != np.uint32):
                    tile = tile.astype(np.uint32)

                if (_format == 'I;16' and tile.dtype != np.uint16):
                    if tile.dtype == np.uint8:
                        tile = 255 * tile.astype(np.uint16)
                    else:
                        # TODO: real support for uint32, signed values, and floats
                        tile = np.clip(tile, 0, 65535).astype(np.uint16)

            return Image.fromarray(tile, _format)

        elif self.reader == 'openslide':
            l = self.dz.level_count - 1 - level
            img = self.dz.get_tile(l, (tx, ty))
            return img

    def save_mask_tiles(self, filename, mask_params, logger, tile_size, level,
                        tx, ty):

        should_skip_tile = {}

        def get_empty_path(path):
            basename = os.path.splitext(path)[0]
            return pathlib.Path(f'{basename}_tmp.txt')

        for image_params in mask_params['images']:

            output_file = str(image_params['out_path'] / filename)
            path_exists = os.path.exists(output_file) or os.path.exists(
                get_empty_path(output_file))
            should_skip = path_exists and image_params['is_up_to_date']
            should_skip_tile[output_file] = should_skip

        if all(should_skip_tile.values()):
            logger.warning(f'Not saving tile level {level} ty {ty} tx {tx}')
            logger.warning(
                f'Every mask {filename} exists with same rendering settings')
            return

        if self.reader == 'tifffile':
            num_channels = self.get_shape()[0]
            tile = self.get_tifffile_tile(num_channels, level, tx, ty, 0,
                                          tile_size)

            for image_params in mask_params['images']:

                output_file = str(image_params['out_path'] / filename)
                if should_skip_tile[output_file]:
                    continue

                target = np.zeros(tile.shape + (4, ), np.uint8)
                skip_empty_tile = True

                for channel in image_params['settings']['channels']:
                    rgba_color = [
                        int(255 * i)
                        for i in (colors.to_rgba(channel['color']))
                    ]
                    ids = channel['ids']

                    if len(ids) > 0:
                        bool_tile = np.isin(tile, ids)
                        # Signal that we must actually save the image
                        if not skip_empty_tile or np.any(bool_tile):
                            skip_empty_tile = False
                        target[bool_tile] = rgba_color
                    else:
                        # Note, any channel without ids to map will override all others
                        target = colorize_mask(target, tile)
                        skip_empty_tile = False

                if skip_empty_tile:
                    empty_file = get_empty_path(output_file)
                    if not os.path.exists(empty_file):
                        with open(empty_file, 'w') as fp:
                            pass
                else:
                    img = Image.frombytes('RGBA', target.T.shape[1:],
                                          target.tobytes())
                    img.save(output_file, quality=85)

    def save_tile(self, output_file, settings, tile_size, level, tx, ty):
        if self.reader == 'tifffile' and self.is_rgba('3 channel'):

            num_channels = self.get_shape()[0]
            tile_0 = self.get_tifffile_tile(num_channels, level, tx, ty, 0,
                                            tile_size)
            tile_1 = self.get_tifffile_tile(num_channels, level, tx, ty, 1,
                                            tile_size)
            tile_2 = self.get_tifffile_tile(num_channels, level, tx, ty, 2,
                                            tile_size)
            tile = np.zeros((tile_0.shape[0], tile_0.shape[1], 3),
                            dtype=np.uint8)
            tile[:, :, 0] = tile_0
            tile[:, :, 1] = tile_1
            tile[:, :, 2] = tile_2

            img = Image.fromarray(tile, 'RGB')
            img.save(output_file, quality=85)

        elif self.reader == 'tifffile' and self.is_rgba('1 channel'):

            num_channels = self.get_shape()[0]
            tile = self.get_tifffile_tile(num_channels, level, tx, ty, 0,
                                          tile_size)

            img = Image.fromarray(tile, 'RGB')
            img.save(output_file, quality=85)

        elif self.reader == 'tifffile':
            target = None
            for i, (marker, color, start, end) in enumerate(
                    zip(settings['Channel Number'], settings['Color'],
                        settings['Low'], settings['High'])):
                num_channels = self.get_shape()[0]
                tile = self.get_tifffile_tile(num_channels, level, tx, ty,
                                              int(marker), tile_size)

                if (tile.dtype != np.uint16):
                    if tile.dtype == np.uint8:
                        tile = 255 * tile.astype(np.uint16)
                    else:
                        tile = tile.astype(np.uint16)

                if i == 0 or target is None:
                    target = np.zeros(tile.shape + (3, ), np.float32)

                composite_channel(target, tile, colors.to_rgb(color),
                                  float(start), float(end))

            if target is not None:
                np.clip(target, 0, 1, out=target)
                target_u8 = (target * 255).astype(np.uint8)
                img = Image.frombytes('RGB', target.T.shape[1:],
                                      target_u8.tobytes())
                img.save(output_file, quality=85)

        elif self.reader == 'openslide':
            l = self.dz.level_count - 1 - level
            img = self.dz.get_tile(l, (tx, ty))
            img.save(output_file, quality=85)
예제 #38
0
def tile(image_file,
         outdir,
         std_img,
         stepsize,
         full_width_region,
         path_to_slide="../images/"):
    slide = OpenSlide(path_to_slide + image_file)
    slp = str(path_to_slide + image_file)

    assert 'openslide.bounds-height' in slide.properties
    assert 'openslide.bounds-width' in slide.properties
    assert 'openslide.bounds-x' in slide.properties
    assert 'openslide.bounds-y' in slide.properties

    x = int(slide.properties['openslide.bounds-x'])
    y = int(slide.properties['openslide.bounds-y'])
    bounds_height = int(slide.properties['openslide.bounds-height'])
    bounds_width = int(slide.properties['openslide.bounds-width'])

    n_x = int((bounds_width - 1) / stepsize)
    n_y = int((bounds_height - 1) / stepsize)

    residue_x = int((bounds_width - n_x * stepsize) / 50)
    residue_y = int((bounds_height - n_y * stepsize) / 50)
    lowres = slide.read_region(
        (x, y), 2, (int(n_x * stepsize / 16), int(n_y * stepsize / 16)))
    lowres = np.array(lowres)[:, :, :3]

    x0 = 0
    # create multiporcessing pool
    print(mp.cpu_count())
    pool = mp.Pool(processes=8)
    tasks = []
    while x0 < n_x:
        task = tuple(
            (slp, n_y, x, y, full_width_region, stepsize, x0, outdir, std_img))
        tasks.append(task)
        x0 += 1
    # slice images with multiprocessing
    temp = pool.starmap(v_slide, tasks)
    tempdict = list(zip(*temp))[0]
    tempimglist = list(zip(*temp))[1]
    temp = None
    pool.close()
    pool.join()

    tempdict = list(filter(None, tempdict))
    imloc = []
    list(map(imloc.extend, tempdict))
    imlocpd = pd.DataFrame(imloc,
                           columns=[
                               "X_pos", "Y_pos", "X", "Y", "X_relative",
                               "Y_relative", "file"
                           ])
    imlocpd = imlocpd.sort_values(["X_pos", "Y_pos"], ascending=[True, True])
    imlocpd = imlocpd.reset_index(drop=True)
    imlocpd = imlocpd.reset_index(drop=False)
    imlocpd.columns = [
        "Num", "X_pos", "Y_pos", "X", "Y", "X_relative", "Y_relative", "file"
    ]
    imlocpd.to_csv(outdir + "/dict.csv", index=False)
    tempdict = None

    tempimglist = list(filter(None, tempimglist))
    imglist = []
    list(map(imglist.extend, tempimglist))
    ct = len(imloc)
    tempimglist = None
    imglist = np.asarray(imglist)

    return n_x, n_y, lowres, residue_x, residue_y, imglist, ct
예제 #39
0
 def _get_label_slide(self):
     if self._label_slide is None and self._label_tif_path is not None:
         self._label_slide = (self._label_tif_path
                              and OpenSlide(str(self._label_tif_path)))
     return self._label_slide
class QtCustomWindow( qt.QWidget ):
    def __init__( self, parent = None ) :
        qt.QWidget.__init__( self, parent )
        self.current_x=0
        self.current_y=0
        #read region always works in the level 0 reference for reading locations
        self.current_zoom=0
        self.image_width=750
        self.image_height=750
        self.setWindowTitle('Large scale image viewing module')
        self.resize(self.image_width,self.image_height)
        self.hbox = qt.QHBoxLayout(self)
        self.lbl = qt.QLabel(self)
        sp=qt.QSizePolicy() # Size policy setting
        sp.setHorizontalPolicy(qt.QSizePolicy.Ignored)
        sp.setVerticalPolicy(qt.QSizePolicy.Ignored)
        self.lbl.setSizePolicy(sp)
        self.setLayout(self.hbox)
        self.filename=None
      
        #
        #self.mouseInitialPosition
        self.panningLock=False
        self.zoomingLock=False
        self.resizeLock=True
        
        self.initUI()
        
        
    def initUI(self):      
        # initialize the widget, make the openslide object pointing to the
        # multilevel image and initialize the view to the top left corner

        if self.filename is not None:
            # openSlide object
            self.osr = OS(self.filename)
            self.level_count = self.osr.level_count
            self.current_x=0
            self.current_y=0
            self.current_zoom=self.level_count-1
            self.level_dimensions=self.osr.level_dimensions
            self.step =int(64*self.osr.level_downsamples[self.current_zoom])
            self.hbox.addWidget(self.lbl)
            self.updatePixmap()
            self.show()
            self.resizeLock=False
        
        
    def updatePixmap(self):
        self.panningLock=True
        
        im=self.osr.read_region((self.current_x,self.current_y),self.current_zoom,(self.image_width,self.image_height))
        
        data = im.tostring('raw', 'RGBA')
        image = qt.QImage(data, im.size[0], im.size[1], qt.QImage.Format_ARGB32)
        pix = qt.QPixmap.fromImage(image)
        self.lbl.setPixmap(pix)
        self.lbl.show()
        
        self.panningLock=False      
    def keyPressEvent( self, event ) :
        key = event.text()
        if key=="s":
            
            self.current_y += self.step 
            self.current_y = min(self.current_y,int(
                self.level_dimensions[0][1]-self.image_height*self.osr.level_downsamples[self.current_zoom]))
        elif key=="w":
            #larger steps for zoomed out images
            self.current_y -= self.step
            self.current_y = max(0, self.current_y)
        elif key=="a":
            #larger steps for zoomed out images
            self.current_x -= self.step
            self.current_x = max(0, self.current_x)
        elif key=="d":
            #larger steps for zoomed out images
            self.current_x += self.step
            self.current_x = min(self.current_x,int(
                self.level_dimensions[0][0]-self.image_width*self.osr.level_downsamples[self.current_zoom]))
        elif key=="q":
            new_zoom = min(self.current_zoom+1,self.level_count-1)
            self.updateCorner(new_zoom)           
            
        elif key=="e":
            new_zoom = max(self.current_zoom-1,0)
            self.updateCorner(new_zoom)

#         print "x: %s" % self.current_x
#         print "y: %s" % self.current_y
#         print "zoom: %s" % self.current_zoom
#         print "downsample: %s" % self.osr.level_downsamples[self.current_zoom]
        self.updatePixmap()
    def updateCorner(self,new_zoom, new_center=None):
        #updates the current_x and current_y values to preserve the desired image center
        
        if new_center:
            center_x=new_center[0]
            center_y=new_center[1]            
        else:
            center_x=self.image_width /2
            center_y=self.image_height /2
        
        
        #while zooming
        self.current_x=int(self.current_x + center_x *self.osr.level_downsamples[self.current_zoom]- self.image_width /2  * self.osr.level_downsamples[new_zoom])
        self.current_y=int(self.current_y + center_y *self.osr.level_downsamples[self.current_zoom]- self.image_height /2 * self.osr.level_downsamples[new_zoom])
        #update step size and current zoom
        self.current_zoom=new_zoom
        
        #larger steps for zoomed out images
        self.step =int(64*self.osr.level_downsamples[self.current_zoom])

################################################################################
################################################################################
    def mousePressEvent(self, QMouseEvent):
        #cursor =qt.QCursor()
        position = QMouseEvent.pos()
        xpos = QMouseEvent.x()
        ypos = QMouseEvent.y()

        self.mouseInitialPosition=np.array([QMouseEvent.x(), QMouseEvent.y()])


       
    def mouseMoveEvent(self, QMouseEvent):
        #cursor =qt.QCursor()
        
        if self.panningLock:
            return
        
        
        currentPosition=np.array([QMouseEvent.x(), QMouseEvent.y()])
        difference=self.mouseInitialPosition-currentPosition
        self.mouseInitialPosition=currentPosition 
          
          
        self.current_x= self.current_x + int(difference[0]*self.osr.level_downsamples[self.current_zoom])
        self.current_x = max(0, self.current_x)
        self.current_x = min(self.current_x,int(
            self.level_dimensions[0][0]-self.image_width*self.osr.level_downsamples[self.current_zoom]))
        
        self.current_y= self.current_y + int(difference[1]*self.osr.level_downsamples[self.current_zoom])
        self.current_y = max(0, self.current_y) 
        self.current_y = min(self.current_y,int(
            self.level_dimensions[0][1]-self.image_height*self.osr.level_downsamples[self.current_zoom]))
            
        self.updatePixmap()
        
    def wheelEvent(self,QMouseEvent):      
        new_zoom = min(max(self.current_zoom- QMouseEvent.delta()/120,0), self.level_count-1)
        
        if new_zoom != self.current_zoom:
            new_center=[0,0]
            new_center[0]= int(QMouseEvent.x())
            new_center[1]= int(QMouseEvent.y())

            
            self.updateCorner(new_zoom, new_center)
            self.updatePixmap()

    def resizeEvent(self,event):
         
        if self.resizeLock:
            return
         
        self.resizeLock=True
        
        difw=event.size().width()-event.oldSize().width()
        difh = event.size().height()-event.oldSize().height()
          
        self.image_width+=difw
        self.image_height+=difh
        self.updatePixmap()
        self.resizeLock=False
예제 #41
0
    def __downscale_slide(self, slide: OpenSlide, slide_path: Path):
        # logging.info("Downscaling a slide...")
        original_width, original_height = slide.dimensions
        # logging.info(f"original dims: {(original_width, original_height)}")

        if self._min_dim_size:
            downscale_factor = self._calc_downscale_factor(slide)
        else:
            downscale_factor = self._downscale_factor

        # logging.info(f"downscale factor: {downscale_factor}")

        level = slide.get_best_level_for_downsample(downscale_factor)

        # logging.info(f"level: {level}")

        level_width, level_height = slide.level_dimensions[level]
        # logging.info(f"level width={level_width}, height={level_height}")

        # logging.info("calc target dims...")
        target_width, target_height = self._calc_downscaled_sizes(
            slide, downscale_factor)
        # logging.info(f"target dims = {(target_width, target_height)}")

        if level_width * level_height < 1e9:
            # logging.info("Reading region...")
            whole_slide_image = slide.read_region(location=(0, 0),
                                                  level=level,
                                                  size=(level_width,
                                                        level_height))

            # logging.info("Converting to RGB...")
            if self._new_slide_ext.lower() in self._RGB_EXTENSIONS:
                whole_slide_image = whole_slide_image.convert("RGB")

            # logging.info("Resizing...")
            whole_slide_image = whole_slide_image.resize(
                (target_width, target_height), PIL.Image.ANTIALIAS)

            # logging.info("Calculating path...")
            output_path = self._calc_new_wsi_path(slide_path)
            output_path.parent.mkdir(parents=True, exist_ok=True)
            # logging.info("Saving...")
            whole_slide_image.save(output_path)
        else:
            n_vertical_splits = self._find_best_n_splits(level_height)
            n_horizontal_splits = self._find_best_n_splits(level_width)

            # logging.info(f"n_vertical_splits={n_vertical_splits}, n_horizontal_splits={n_horizontal_splits}")

            original_tile_height = math.ceil(original_height /
                                             n_vertical_splits)
            original_tile_width = math.ceil(original_width /
                                            n_horizontal_splits)

            level_tile_height = math.ceil(level_height / n_vertical_splits)
            level_tile_width = math.ceil(level_width / n_horizontal_splits)

            # logging.info(f"level_tile_width:{level_width / n_horizontal_splits} "
            #              f"approx:{math.ceil(level_width / n_horizontal_splits)}")

            # target_tile_height = math.ceil(target_height / n_vertical_splits)
            # target_tile_width = math.ceil(target_width / n_horizontal_splits)

            for i in range(n_vertical_splits):
                for j in range(n_horizontal_splits):
                    y_i = original_tile_height * i
                    x_j = original_tile_width * j
                    # logging.info(f"x_j={x_j}, y_i={y_i}")

                    level_height_i = min(level_tile_height,
                                         level_height - level_tile_height * i)
                    # target_height_i = min(target_tile_height, target_tile_height * (n_vertical_splits - 1))

                    level_width_j = min(level_tile_width,
                                        level_width - level_tile_width * j)
                    # target_width_j = min(target_tile_width, target_tile_width * (n_horizontal_splits - 1))

                    # logging.info(f"level height_i={level_height_i}, width_j={level_width_j}")
                    # logging.info(f"target height_i={target_height_i}, width_j={target_width_j}")

                    # logging.info(f"Reading region {i}_{j}...")
                    whole_slide_image_tile = slide.read_region(
                        location=(x_j, y_i),
                        level=level,
                        size=(level_width_j, level_height_i))

                    # logging.info(f"Converting to RGB {i}_{j}...")
                    whole_slide_image_tile = whole_slide_image_tile.convert(
                        "RGB")

                    # logging.info("Resizing...")
                    # whole_slide_image_tile = whole_slide_image_tile.resize((target_width_j, target_height_i),
                    #                                                        PIL.Image.ANTIALIAS)

                    # logging.info("Calculating path...")
                    output_path = self._calc_new_wsi_path(slide_path,
                                                          part=f"{i}_{j}")
                    output_path.parent.mkdir(parents=True, exist_ok=True)
                    # logging.info("Saving...")
                    whole_slide_image_tile.save(output_path)
예제 #42
0
def run(filename, split, level, dred, dbrown, debug):

# Create OpenSlide object
	ndpi         = OpenSlide(filename)
	ndpi_width   = ndpi.dimensions[0]
	ndpi_height  = ndpi.dimensions[1]
	total_width  = ndpi.level_dimensions[level][0]
	total_height = ndpi.level_dimensions[level][1]
	
	red_sum     = 0.0
	brown_sum   = 0.0
	surface_sum = 0.0

	startTime    = time.time()

	if debug:
		print "filename: {}".format(filename)
		print "split: {}".format(split)
		print "level: {}".format(level)
		print "dred: {}".format(dred)
		print "dbrown: {}".format(dbrown)
		print "debug: {}".format(debug)


	if debug:
		print "================ START ================="
		print "LOAD {}".format(filename)
		print "width:".ljust(20) + str(ndpi_width)
		print "height:".ljust(20) + str(ndpi_height)
		print "level count:".ljust(20) + str(ndpi.level_count)
		print "split image {}x{} , level:{} , factor:{}".format(total_width,total_height,level,split)
		
	bar = Bar('Processing', max=split**2)
	for i in range(split):
		for j in range(split):
			x     = i * ndpi_width / split
			y     = j * ndpi_height / split
			w     = total_width / split
			h     = total_height / split

			if debug:
				print "\n>SLICE [{}][{}]".format(i,j)
				print "x:{:3} y:{:3} w:{:3}px h:{:3}px:".format(x,y,w,h)

			region  = ndpi.read_region((x,y), level, (w, h))
			red     = bgsa.get_red(region, brightness=-dred)
			brown   = bgsa.get_brown(region, brightness=-dbrown)
			# surface = bgsa.get_surface(region)

			region.save("output/normal_slice{}{}.png".format(i,j))
			red.save("output/red_slice_{}{}.png".format(i,j))
			brown.save("output/brown_slice_{}{}.png".format(i,j))
			# surface.save("output/surface_slice_{}{}.png".format(i,j))

			red_sum    += bgsa.get_white_pixels(red)
			brown_sum  += bgsa.get_white_pixels(brown)
			# surface_sum+= bgsa.get_white_pixels(surface)

			if debug:
				bar.next()

			
			# print "white:{}% black{}%".format(results["white"], results["black"])

	if debug:
		bar.finish()
		print "Finished....in {:.2f} sec".format(time.time() - startTime)
		print "total red   :".ljust(20) + str(red_sum)
		print "total brown :".ljust(20) + str(brown_sum)

	return {"red":red_sum, "brown":brown_sum}
예제 #43
0
    def inferenceLoopPath(inferenceDataFromPickle, headers, device, parameters,
                          outputDir):
        from GANDLF.inference_dataloader_histopath import InferTumorSegDataset
        from openslide import OpenSlide
        '''
        This is the main inference loop for histopathology
        '''
        # extract variables form parameters dict
        patch_size = parameters['patch_size']
        stride = parameters['stride_size']
        augmentations = parameters['data_augmentation']
        preprocessing = parameters['data_preprocessing']
        which_model = parameters['model']['architecture']
        class_list = parameters['model']['class_list']
        base_filters = parameters['model']['base_filters']
        amp = parameters['model']['amp']
        batch_size = parameters['batch_size']
        n_channels = len(headers['channelHeaders'])
        if not ('n_channels' in parameters['model']):
            n_channels = len(headers['channelHeaders'])
        else:
            n_channels = parameters['model']['n_channels']
        n_classList = len(class_list)
        # Report the time stamp
        training_start_time = time.asctime()
        startstamp = time.time()
        print("\nHostname   :" + str(os.getenv("HOSTNAME")))
        print("\nStart Time :" + str(training_start_time))
        print("\nStart Stamp:" + str(startstamp))
        sys.stdout.flush()

        # PRINT PARSED ARGS
        print("\n\n")
        print("Output directory        :", outputDir)
        if 'n_channels' in parameters['model']:
            print("Number of channels      :",
                  parameters['model']['n_channels'])
        print("Modalities              :", parameters['modality'])
        #print("Number of classes       :", parameters['modality']['num_classes']
        print("Batch Size              :", parameters['batch_size'])
        print("Patch Size              :", parameters['patch_size'])
        print("Sampling Stride         :", parameters['stride_size'])
        print("Base Filters            :", parameters['model']['base_filters'])
        #print("Load Weights            :", parameters['load_weights'])
        sys.stdout.flush()
        # We generate CSV for training if not provided
        print("Reading CSV Files")
        n_classList = len(class_list)
        #test_csv = parameters['test_csv']

        # Defining our model here according to parameters mentioned in the configuration file
        print("Number of dims     : ", parameters['model']['dimension'])
        if 'n_channels' in parameters['model']:
            print("Number of channels : ", parameters['model']['n_channels'])
        print("Number of classes  : ", n_classList)
        model = get_model(
            which_model,
            n_dimensions=parameters['model']['dimension'],
            n_channels=n_channels,
            n_classes=n_classList,
            base_filters=base_filters,
            final_convolution_layer=parameters['model']['final_layer'],
            psize=patch_size,
            batch_size=batch_size)

        # Loading the weights into the model
        main_dict = torch.load(
            os.path.join(outputDir,
                         str(which_model) + "_best_val.pth.tar"))
        model.load_state_dict(main_dict['model_state_dict'])
        print('Loaded Weights successfully.')
        sys.stdout.flush()

        model, amp, device = send_model_to_device(model,
                                                  amp,
                                                  device,
                                                  optimizer=None)

        model.eval()
        # print stats
        print('Using device:', device)
        sys.stdout.flush()

        test_df = inferenceDataFromPickle
        # Patch blocks

        for index, row in test_df.iterrows():
            subject_name = row[headers['subjectIDHeader']]
            print("Patient Slide       : ", row[headers['subjectIDHeader']])
            print("Patient Location    : ", row[headers['channelHeaders']])
            print(row[headers['channelHeaders']].values[0])
            os_image = OpenSlide(row[headers['channelHeaders']].values[0])
            level_width, level_height = os_image.level_dimensions[int(
                parameters['slide_level'])]
            subject_dest_dir = os.path.join(outputDir, subject_name)
            os.makedirs(subject_dest_dir, exist_ok=True)

            probs_map = np.zeros((level_height, level_width), dtype=np.float16)
            count_map = np.zeros((level_height, level_width), dtype=np.uint8)

            patient_dataset_obj = InferTumorSegDataset(
                row[headers['channelHeaders']].values[0],
                patch_size=patch_size,
                stride_size=stride,
                selected_level=parameters['slide_level'],
                mask_level=4)

            dataloader = DataLoader(patient_dataset_obj,
                                    batch_size=int(parameters['batch_size']),
                                    shuffle=False,
                                    num_workers=2)
            for image_patches, (x_coords, y_coords) in tqdm(dataloader):
                x_coords, y_coords = y_coords.numpy(), x_coords.numpy()
                with autocast():
                    output = model(image_patches.half().cuda())
                output = output.cpu().detach().numpy()
                for i in range(int(output.shape[0])):
                    count_map[x_coords[i]:x_coords[i] + patch_size[0],
                              y_coords[i]:y_coords[i] + patch_size[1]] += 1
                    probs_map[x_coords[i]:x_coords[i] + patch_size[0],
                              y_coords[i]:y_coords[i] +
                              patch_size[1]] += output[i][0]
            probs_map = probs_map / count_map
            count_map = (count_map / count_map.max())
            out = count_map * probs_map
            count_map = np.array(count_map * 255, dtype=np.uint16)
            out_thresh = np.array((out > 0.5) * 255, dtype=np.uint16)
            imsave(
                os.path.join(subject_dest_dir,
                             row[headers['subjectIDHeader']] + '_prob.png'),
                out)
            imsave(
                os.path.join(subject_dest_dir,
                             row[headers['subjectIDHeader']] + '_seg.png'),
                out_thresh)
            imsave(
                os.path.join(subject_dest_dir,
                             row[headers['subjectIDHeader']] + '_count.png'),
                count_map)
예제 #44
0
 def osh(self):
     return OpenSlide(self.file_name)
예제 #45
0
def main(dirr, imgfile, bs, md, modeltoload, meta_cut, pdmd, LOG_DIR,
         METAGRAPH_DIR):
    start_time = time.time()
    if pdmd == 'histology':
        pos_score = "Serous_score"
        neg_score = "Endometrioid_score"
    elif pdmd == 'MSIst':
        pos_score = "MSI-H_score"
        neg_score = "MSS_score"
    else:
        pos_score = "POS_score"
        neg_score = "NEG_score"
    # make directories if not exist
    for DIR in (LOG_DIR, METAGRAPH_DIR, data_dir, out_dir):
        try:
            os.mkdir(DIR)
        except FileExistsError:
            pass
    if "TCGA" in imgfile:
        ft = 1
        level = 1
    else:
        level = 0
        ft = 2
    slide = OpenSlide("../images/" + imgfile)

    bounds_width = slide.level_dimensions[level][0]
    bounds_height = slide.level_dimensions[level][1]
    x = 0
    y = 0
    half_width_region = 49 * ft
    full_width_region = 299 * ft
    stepsize = (full_width_region - half_width_region)

    n_x = int((bounds_width - 1) / stepsize)
    n_y = int((bounds_height - 1) / stepsize)

    lowres = slide.read_region(
        (x, y), level + 1, (int(n_x * stepsize / 4), int(n_y * stepsize / 4)))
    raw_img = np.array(lowres)[:, :, :3]
    fct = ft

    if not os.path.isfile(data_dir + '/level1/dict.csv'):
        cutter(imgfile, meta_cut, cut)

    if not os.path.isfile(data_dir + '/test.tfrecords'):
        loader(data_dir, imgfile)
    if not os.path.isfile(data_dir + '/out/Overlay.png'):
        test(bs, 2, modeltoload, LOG_DIR, METAGRAPH_DIR)
        slist = pd.read_csv(data_dir + '/te_sample.csv', header=0)
        # load dictionary of predictions on tiles
        teresult = pd.read_csv(out_dir + '/Test.csv', header=0)
        # join 2 dictionaries
        joined = pd.merge(slist, teresult, how='inner', on=['Num'])
        joined = joined.drop(columns=['Num'])
        tile_dict = pd.read_csv(data_dir + '/level1/dict.csv', header=0)
        tile_dict = tile_dict.rename(index=str, columns={"Loc": "L0path"})
        joined_dict = pd.merge(joined, tile_dict, how='inner', on=['L0path'])

        if joined_dict[pos_score].mean() > 0.5:
            print("Positive! Prediction score = " +
                  str(joined_dict[pos_score].mean().round(5)))
        else:
            print("Negative! Prediction score = " +
                  str(joined_dict[pos_score].mean().round(5)))
        # save joined dictionary
        joined_dict.to_csv(out_dir + '/finaldict.csv', index=False)

        # output heat map of pos and neg.
        # initialize a graph and for each RGB channel
        opt = np.full((n_x, n_y), 0)
        hm_R = np.full((n_x, n_y), 0)
        hm_G = np.full((n_x, n_y), 0)
        hm_B = np.full((n_x, n_y), 0)

        # Positive is labeled red in output heat map
        for index, row in joined_dict.iterrows():
            opt[int(row["X_pos"]), int(row["Y_pos"])] = 255
            if row[pos_score] >= 0.5:
                hm_R[int(row["X_pos"]), int(row["Y_pos"])] = 255
                hm_G[int(row["X_pos"]), int(row["Y_pos"])] = int(
                    (1 - (row[pos_score] - 0.5) * 2) * 255)
                hm_B[int(row["X_pos"]), int(row["Y_pos"])] = int(
                    (1 - (row[pos_score] - 0.5) * 2) * 255)
            else:
                hm_B[int(row["X_pos"]), int(row["Y_pos"])] = 255
                hm_G[int(row["X_pos"]), int(row["Y_pos"])] = int(
                    (1 - (row[neg_score] - 0.5) * 2) * 255)
                hm_R[int(row["X_pos"]), int(row["Y_pos"])] = int(
                    (1 - (row[neg_score] - 0.5) * 2) * 255)

        # expand 5 times
        opt = opt.repeat(50, axis=0).repeat(50, axis=1)

        # small-scaled original image
        ori_img = cv2.resize(raw_img, (np.shape(opt)[0], np.shape(opt)[1]))
        ori_img = ori_img[:np.shape(opt)[1], :np.shape(opt)[0], :3]
        tq = ori_img[:, :, 0]
        ori_img[:, :, 0] = ori_img[:, :, 2]
        ori_img[:, :, 2] = tq
        cv2.imwrite(out_dir + '/Original_scaled.png', ori_img)

        # binary output image
        topt = np.transpose(opt)
        opt = np.full((np.shape(topt)[0], np.shape(topt)[1], 3), 0)
        opt[:, :, 0] = topt
        opt[:, :, 1] = topt
        opt[:, :, 2] = topt
        cv2.imwrite(out_dir + '/Mask.png', opt * 255)

        # output heatmap
        hm_R = np.transpose(hm_R)
        hm_G = np.transpose(hm_G)
        hm_B = np.transpose(hm_B)
        hm_R = hm_R.repeat(50, axis=0).repeat(50, axis=1)
        hm_G = hm_G.repeat(50, axis=0).repeat(50, axis=1)
        hm_B = hm_B.repeat(50, axis=0).repeat(50, axis=1)
        hm = np.dstack([hm_B, hm_G, hm_R])
        cv2.imwrite(out_dir + '/HM.png', hm)

        # superimpose heatmap on scaled original image
        overlay = ori_img * 0.5 + hm * 0.5
        cv2.imwrite(out_dir + '/Overlay.png', overlay)
예제 #46
0
 def _get_openslide_wrapper(self, original_file_source, file_mimetype):
     img_path = self._get_image_path(original_file_source, file_mimetype)
     if img_path:
         return OpenSlide(img_path)
     else:
         return None
예제 #47
0
    def __init__(self,
                 path,
                 root,
                 src_size,
                 patch_size,
                 fetch_mode='area',
                 label_to_use=0,
                 rotation=True,
                 flip=False,
                 blur=0,
                 he_augmentation=False,
                 scale_augmentation=False,
                 color_matching=None,
                 dump_patch=None,
                 verbose=1):
        self.path = path
        self.root = root
        self.src_size = src_size
        self.patch_size = patch_size
        self.fetch_mode = fetch_mode
        self.label_to_use = label_to_use
        if self.fetch_mode not in OpenSlideGenerator.fetch_modes:
            raise Exception('invalid fetch_mode %r' % self.fetch_mode)
        self.rotation = rotation
        self.flip = flip
        self.blur = blur
        self.he_augmentation = he_augmentation
        self.scale_augmentation = scale_augmentation
        self.dump_patch = dump_patch
        self.verbose = verbose

        self.use_color_matching = False
        if color_matching is not None:
            self.match_color_prepare(cv2.imread(color_matching) / 255.0)
            self.use_color_matching = True

        self.slide_names = []
        self.labels = []  # labels[LABEL_CATEGORY][LABEL]
        self.label_of_region = []
        self.structure = []
        self.shifted_structure = []
        self.triangulation = []
        self.regions_of_label = []  # dict()
        self.regions_of_label_slide = []  # dict()

        self.src_sizes = []

        self.total_weight = 0
        self.slide_weights = []  # total weight of a slide
        self.label_weights = []  # total weight of a label
        self.label_slide_weights = [
        ]  # total weight of regions of certain label in a slide.

        self.weights = []  # overall weight
        self.weights_in_slide = []  # weight in a slide
        self.weights_in_label = []  # weight in the same label
        self.weights_in_label_slide = []  # weight in the same label and slide

        self.total_area = 0
        self.slide_areas = []  # total area of a slide
        self.label_areas = []  # total area of a label

        self.total_triangles = 0
        self.slide_triangles = []  # total triangle number for each slide
        self.label_triangles = []  # total triangle number for each label
        self.label_slide_triangles = [
        ]  # total triangule number for each label-slide pair

        self.serialized_index = [
        ]  # serialized_index[ID] -> (SLIDE_ID, REGION_ID, TRIANGLE_ID)
        self.serialized_index_slide = [
        ]  # serialized_index_slide[SLIDE_ID][ID] -> (REGION_ID, TRIANGLE_ID)
        self.serialized_index_label = [
        ]  # serialized_index_label[label][ID] -> (SLIDE_ID, REGION_ID, TRIANGLE_ID)
        self.serialized_index_label_slide = [
        ]  # *[label][SLIDE_ID][ID] -> (REGION_ID, TRIANGLE_ID)

        # variables for Walker's alias method
        self.a_area = []
        self.p_area = []
        self.a_slide = []
        self.p_slide = []
        self.a_label = []
        self.p_label = []
        self.a_label_slide = []
        self.p_label_slide = []

        # OpenSlide objects
        self.slides = []

        # log
        self.fetch_count = []  # region-wise

        # states for parsing input text file
        # 0: waiting for new file entry
        # 1: waiting for region header or svs entry
        # 2: reading a region
        state = 0
        left_points = 0
        label_buffer = []  # label_buffer[SLIDE_ID][REGION_ID][LABEL_CATEGORY]
        slide_id = -1
        region_id = -1
        with open(path) as f:
            for line in map(lambda l: l.split("#")[0].strip(), f.readlines()):
                if len(line) == 0:
                    continue
                is_svs_line = (line[0] == "@")
                if is_svs_line:
                    line = line[1:]
                else:
                    try:
                        items = list(map(int, line.split()))
                    except Exception:
                        raise Exception('invalid dataset file format!')
                if state == 0:
                    if not is_svs_line:
                        raise Exception('invalid dataset file format!')

                    slide_id += 1
                    region_id = 0
                    svs_name = line.split()[0]
                    if len(line.split()) > 1 and line.split()[1].isdigit:
                        svs_src_size = int(line.split()[1])
                    else:
                        svs_src_size = self.src_size

                    self.slide_names.append(svs_name)
                    self.src_sizes.append(svs_src_size)
                    self.structure.append([])
                    label_buffer.append([])
                    state = 1
                elif state == 1:
                    if is_svs_line:  # new file
                        slide_id += 1
                        region_id = 0
                        svs_name = line.split()[0]
                        if len(line.split()) > 1 and line.split()[1].isdigit:
                            svs_src_size = int(line.split()[1])
                        else:
                            svs_src_size = self.src_size  # default src_size

                        self.slide_names.append(svs_name)
                        self.src_sizes.append(svs_src_size)
                        self.structure.append([])
                        label_buffer.append([])
                        state = 1
                    else:  # region header
                        label_buffer[slide_id].append([])
                        for label_cat, label in enumerate(items[:-1]):
                            label_buffer[slide_id][region_id].append(label)
                            # handling newly found label category
                            if len(self.labels) < label_cat + 1:
                                self.labels.append([])
                                self.regions_of_label.append(dict())
                                self.regions_of_label_slide.append(dict())
                                self.a_label.append(dict())
                                self.p_label.append(dict())
                                self.a_label_slide.append(dict())
                                self.p_label_slide.append(dict())
                                self.label_areas.append(dict())
                                self.label_weights.append(dict())
                                self.label_slide_weights.append(dict())
                                self.label_triangles.append(dict())
                                self.label_slide_triangles.append(dict())
                                self.serialized_index_label.append(dict())
                                self.serialized_index_label_slide.append(
                                    dict())
                            # handling newly found label
                            if label not in self.labels[label_cat]:
                                self.labels[label_cat].append(label)
                                self.regions_of_label[label_cat][label] = []
                                self.a_label[label_cat][label] = []
                                self.p_label[label_cat][label] = []
                                self.a_label_slide[label_cat][label] = []
                                self.p_label_slide[label_cat][label] = []
                                self.label_areas[label_cat][label] = 0
                                self.label_weights[label_cat][label] = 0
                                self.label_slide_weights[label_cat][label] = []
                                self.label_triangles[label_cat][label] = 0
                                self.label_slide_triangles[label_cat][
                                    label] = []
                                self.serialized_index_label[label_cat][
                                    label] = []
                                self.serialized_index_label_slide[label_cat][
                                    label] = []
                            self.regions_of_label[label_cat][label].append(
                                (slide_id, region_id))
                        self.structure[slide_id].append([])
                        left_points = items[-1]
                        if items[-1] < 3:
                            raise Exception(
                                'regions should consist of more than 3 points!'
                            )
                        state = 2
                elif state == 2:
                    if is_svs_line or len(items) != 2:
                        raise Exception('invalid dataset file format!')
                    self.structure[-1][-1].append((items[0], items[1]))
                    left_points -= 1
                    if left_points == 0:
                        state = 1
                        region_id += 1
        if state != 1:  # dataset file should end with a completed region entry
            raise Exception('invalid dataset file format!')

        # set label_of_region
        for label_cat in range(len(self.labels)):
            self.label_of_region.append([])
            for slide_id, label_of_regions in enumerate(label_buffer):
                self.label_of_region[label_cat].append([])
                for region_id, label_of_categories in enumerate(
                        label_of_regions):
                    if label_cat < len(label_of_categories):
                        self.label_of_region[label_cat][slide_id].append(
                            label_of_categories[label_cat])
                    else:
                        self.label_of_region[label_cat][slide_id].append(-1)

        # calculate regions_of_label_slide
        for label_cat in range(len(self.labels)):
            for label in self.labels[label_cat]:
                self.regions_of_label_slide[label_cat][label] = []
                for i in range(len(self.structure)):
                    self.regions_of_label_slide[label_cat][label].append([])

        # prepare shifted (offset) structure
        self.shifted_structure = copy.deepcopy(self.structure)
        for i in range(len(self.shifted_structure)):
            for j in range(len(self.shifted_structure[i])):
                pco = pyclipper.PyclipperOffset()
                pco.AddPath(self.shifted_structure[i][j], pyclipper.JT_ROUND,
                            pyclipper.ET_CLOSEDPOLYGON)
                # offsetting
                shifted_region = pco.Execute(-self.src_sizes[i] / 2)
                # shifted_region = pco.Execute(0)
                if len(shifted_region) == 0:
                    self.shifted_structure[i][j] = []  # collapsed to a point
                else:
                    self.shifted_structure[i][j] = shifted_region[0]
                    for label_cat in range(len(self.labels)):
                        label = self.label_of_region[label_cat][i][j]
                        if label != -1:
                            self.regions_of_label_slide[label_cat][label][
                                i].append(j)

        # load slides
        for name in self.slide_names:
            try:
                self.slides.append(OpenSlide(os.path.join(self.root, name)))
            except Exception as exc:
                raise Exception(
                    'an error has occurred while reading slide "{}"'.format(
                        name))

        for label_cat in range(len(self.labels)):
            self.weights_in_label.append([])
            self.weights_in_label_slide.append([])

        # region triangulation
        total_region_count = 0
        for i in range(len(self.shifted_structure)):
            self.triangulation.append([])
            self.weights.append([])
            self.weights_in_slide.append([])
            for label_cat in range(len(self.labels)):
                self.weights_in_label[label_cat].append([])
                self.weights_in_label_slide[label_cat].append([])
            self.serialized_index_slide.append([])
            self.a_slide.append([])
            self.p_slide.append([])
            self.slide_weights.append(0)
            self.slide_triangles.append(0)
            w, h = self.slides[i].dimensions  # slide width/height

            for label_cat in range(len(self.labels)):
                for label in self.labels[label_cat]:
                    self.a_label_slide[label_cat][label].append([])
                    self.p_label_slide[label_cat][label].append([])
                    self.serialized_index_label_slide[label_cat][label].append(
                        [])
                    self.label_slide_weights[label_cat][label].append(0)
                    self.label_slide_triangles[label_cat][label].append(0)

            for j in range(len(self.shifted_structure[i])):
                region = self.shifted_structure[i][j]
                total_region_count += 1

                # triangulation
                self.triangulation[-1].append(tripy.earclip(region))

                for x, y in region:
                    if w < x or h < y:
                        raise Exception(
                            'invalid polygon vertex position (%d, %d) in %s!' %
                            (x, y, self.slide_names[i]))

                # triangle area calculation
                self.weights[i].append([])
                self.weights_in_slide[i].append([])
                self.slide_triangles[i] += len(self.triangulation[i][j])

                for label_cat in range(len(self.labels)):
                    self.weights_in_label[label_cat][i].append([])
                    self.weights_in_label_slide[label_cat][i].append([])
                    label = self.label_of_region[label_cat][i][j]
                    if label != -1:
                        self.label_triangles[label_cat][label] += len(
                            self.triangulation[i][j])
                        self.label_slide_triangles[label_cat][label][i] += len(
                            self.triangulation[i][j])

                for (x1, y1), (x2, y2), (x3, y3) in self.triangulation[i][j]:
                    a = x2 - x1
                    b = y2 - y1
                    c = x3 - x1
                    d = y3 - y1
                    area = abs(a * d - b * c) / 2
                    weight = area / (self.src_sizes[i]**2)
                    self.weights[i][j].append(weight)
                    self.weights_in_slide[i][j].append(weight)
                    self.total_weight += weight
                    self.slide_weights[i] += weight
                    for label_cat in range(len(self.labels)):
                        self.weights_in_label[label_cat][i][j].append(weight)
                        self.weights_in_label_slide[label_cat][i][j].append(
                            weight)
                        label = self.label_of_region[label_cat][i][j]
                        if label != -1:
                            self.label_weights[label_cat][label] += weight
                            self.label_slide_weights[label_cat][label][
                                i] += weight

        # calculate raw slide size
        for i in range(len(self.structure)):
            self.slide_areas.append(0)

            for j in range(len(self.structure[i])):
                region = self.structure[i][j]
                triangles = tripy.earclip(region)
                for (x1, y1), (x2, y2), (x3, y3) in triangles:
                    a = x2 - x1
                    b = y2 - y1
                    c = x3 - x1
                    d = y3 - y1
                    area = abs(a * d - b * c) / 2
                    self.total_area += area
                    self.slide_areas[-1] += area
                    for label_cat in range(len(self.labels)):
                        label = self.label_of_region[label_cat][i][j]
                        if label != -1:
                            self.label_areas[label_cat][label] += area

        # calculate the set of triangle weights for each fetch_mode
        for i in range(len(self.weights)):  # svs
            for j in range(len(self.weights[i])):  # region
                for k in range(len(self.weights[i][j])):  # triangle
                    self.weights[i][j][k] /= self.total_weight
                    self.weights_in_slide[i][j][k] /= self.slide_weights[i]
                    self.serialized_index.append((i, j, k))
                    self.serialized_index_slide[i].append((j, k))
                    for label_cat in range(len(self.labels)):
                        label = self.label_of_region[label_cat][i][j]
                        if label != -1:
                            self.weights_in_label[label_cat][i][j][
                                k] /= self.label_weights[label_cat][label]
                            if self.label_slide_weights[label_cat][label][
                                    i] > 0:
                                self.weights_in_label_slide[label_cat][i][j][
                                    k] /= self.label_slide_weights[label_cat][
                                        label][i]
                            self.serialized_index_label[label_cat][
                                label].append((i, j, k))
                            self.serialized_index_label_slide[label_cat][
                                label][i].append((j, k))
                    self.total_triangles += 1

        # Walker's alias method for weighted sampling of triangles
        def walker_precomputation(probs):
            EPS = 1e-10

            # normalization
            prob_sum = 0
            for prob in probs:
                prob_sum += prob
            prob_sum *= (1 + EPS)
            for i in range(len(probs)):
                probs[i] /= prob_sum

            a = [-1] * len(probs)
            p = [0] * len(probs)
            fixed = 0
            while fixed < len(probs):
                # block assignment of small items
                for i in range(len(probs)):
                    if p[i] == 0 and probs[i] * len(probs) <= (1.0 + EPS):
                        p[i] = probs[i] * len(probs)
                        probs[i] = 0
                        fixed += 1
                # packing of large items
                for i in range(len(probs)):
                    if probs[i] * len(probs) > 1.0:
                        for j in range(len(probs)):
                            if p[j] != 0 and a[j] == -1:
                                a[j] = i
                                probs[i] -= (1.0 - p[j]) / len(probs)
                            if probs[i] * len(probs) <= (1.0 + EPS):
                                break

            # fill -1 a
            for i in range(len(probs)):
                if a[i] == -1:
                    a[i] = i
            return a, p

        # pre-computation for 'area' mode - all triangles are treated in single array
        probs = []
        for i in range(len(self.weights)):  # svs
            for j in range(len(self.weights[i])):  # region
                for k in range(len(self.weights[i][j])):  # triangle
                    probs.append(self.weights[i][j][k])
        self.a_area, self.p_area = walker_precomputation(probs)

        # pre-computaiton for 'slide' mode
        for i in range(len(self.weights)):  # svs
            probs = []
            for j in range(len(self.weights[i])):  # region
                for k in range(len(self.weights[i][j])):  # triangle
                    probs.append(self.weights_in_slide[i][j][k])

            self.a_slide[i], self.p_slide[i] = walker_precomputation(probs)

        # pre-computation for 'label' mode
        for label_cat in range(len(self.labels)):
            for label in self.labels[label_cat]:
                probs = []
                for slide_id, region_id in self.regions_of_label[label_cat][
                        label]:
                    for tri_id in range(
                            len(self.weights_in_label[label_cat][slide_id]
                                [region_id])):
                        probs.append(self.weights_in_label[label_cat][slide_id]
                                     [region_id][tri_id])

                self.a_label[label_cat][label], self.p_label[label_cat][
                    label] = walker_precomputation(probs)

        # pre-computation for 'label-slide' mode
        for label_cat in range(len(self.labels)):
            for label in self.labels[label_cat]:
                for slide_id in range(len(self.weights)):
                    probs = []
                    for region_id in self.regions_of_label_slide[label_cat][
                            label][slide_id]:
                        for tri_id in range(
                                len(self.weights_in_label_slide[label_cat]
                                    [slide_id][region_id])):
                            probs.append(self.weights_in_label_slide[label_cat]
                                         [slide_id][region_id][tri_id])
                    self.a_label_slide[label_cat][label][
                        slide_id], self.p_label_slide[label_cat][label][
                            slide_id] = walker_precomputation(probs)

        if self.verbose > 0:
            print('loaded {} slide(s).'.format(len(self.shifted_structure)))
            for i in range(len(self.shifted_structure)):
                print('[{}] {}'.format(i, self.slide_names[i]))
                print('- {} regions'.format(len(self.shifted_structure[i])))
                print('- {} px2'.format(self.slide_areas[i]))
                print('- patch scale:', self.src_sizes[i])
                weight_sum = 0
                for region in self.weights[i]:
                    for w_triangle in region:
                        weight_sum += w_triangle
                print('- fetch probability (area mode):', weight_sum)
            print('there are total {} regions.'.format(total_region_count,
                                                       int(self.total_area)))

        self.patch_per_epoch = 0
        for i in range(len(self.src_sizes)):
            self.patch_per_epoch += self.slide_areas[i] / (self.src_sizes[i]**
                                                           2)
            self.patch_per_epoch = int(self.patch_per_epoch)
        if self.verbose > 0:
            print('patches per epoch is set to {}.'.format(
                self.patch_per_epoch))
            print()

        self.reset_fetch_count()
예제 #48
0
def open_slide(slide):
    return OpenSlide(slide)
예제 #49
0
from openslide import OpenSlide

svs_path = 'Slide 10.svs'

# Open whole slide image
img = OpenSlide(svs_path)

# Get shape
original_dimensions = img.dimensions

# Get thumbnail image (t times smaller)
t = 512
resize_width = original_dimensions[0] / t
resize_height = original_dimensions[1] / t
resized_img = img.get_thumbnail(
    (resize_width, resize_height))  # PIL.Image type
resized_img.save('thumbnail_images_sample/' + svs_path.split('.')[0] + '.png')
# Get a region of the original image (here [10000:10100,10000:10100])
cropped_img = img.read_region((10000, 10000), 0, (100, 100))  # PIL Image RGBA
cropped_img = cropped_img.convert('RGB')  # PIL Image RGB
cropped_img.save('tmp.png')
def extract_patch_on_slide(
        file_path_tif, \
        file_path_tis_mask, \
        file_path_jpg, \
        save_location_path_patch_position_visualize, \
        save_location_path_patch_position_csv, \
        size_patch):
    """
    -- Intput :
    file_path_tif : full path
    file_path_tis_mask : full path
    file_path_jpg : full path
    save_location_path_patch_position_visualize : full path
    save_location_path_patch_position_csv : full path
    -- Result :
    Draw patch position.
    Save coordinate of patch at level_0.
    """
    patch_level = 0
    contours_level = 4
    mask_level = 4

    slide = OpenSlide(file_path_tif)
    slide_w_lv_4, slide_h_lv_4 = slide.level_dimensions[4]
    downsample = slide.level_downsamples[4]
    size_patch_lv_4 = int(size_patch / downsample)

    # Make integral image of slide
    tissue_mask = cv2.imread(file_path_tis_mask, 0)

    integral_image_tissue = integral_image(tissue_mask.T / 255)

    # Load original bgr_jpg_lv_4 for visualizing patch position
    wsi_bgr_jpg = cv2.imread(file_path_jpg)
    wsi_jpg_visualizing_patch_position = wsi_bgr_jpg.copy()

    print('==> making contours of tissue region from jpg ..')

    # Find and Draw contours_tissue - (color : blue)
    _, contours_tissue, _ = cv2.findContours( \
        tissue_mask, \
        cv2.RETR_TREE, \
        cv2.CHAIN_APPROX_SIMPLE)
    cv2.drawContours(wsi_jpg_visualizing_patch_position, \
                     contours_tissue, -1, (255, 0, 0), 2)

    # Make csv_writer
    csv_file = open(save_location_path_patch_position_csv, 'w')
    fieldnames = ['X', 'Y']
    csv_writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
    csv_writer.writeheader()

    print('==> Extracting patches randomly on tissue region...')
    patch_cnt = 0

    ### Extract random patches on tissue region
    for contour in contours_tissue:

        # Check if contour area is samller than patch area
        area = cv2.contourArea(contour)
        area_patch_lv_4 = size_patch_lv_4**2
        if area < area_patch_lv_4:
            continue

        # Determine number of patches to extract
        number_patches = int(round(area / area_patch_lv_4 * 1.5))
        number_patches = min(50, number_patches)
        print('contour area : ', area, ' num_patch : ', number_patches)

        # Get coordinates of contour (level : 4)
        coordinates = (np.squeeze(contour)).T
        coords_x = coordinates[0]
        coords_y = coordinates[1]

        # Bounding box vertex
        p_x_left = np.min(coords_x)
        p_x_right = np.max(coords_x)
        p_y_top = np.min(coords_y)
        p_y_bottom = np.max(coords_y)

        # Make candidates of patch coordinate (level : 4)
        candidate_x = \
            np.arange(round(p_x_left), round(p_x_right)).astype(int)
        candidate_y = \
            np.arange(round(p_y_top), round(p_y_bottom)).astype(int)

        # Pick coordinates randomly
        len_x = candidate_x.shape[0]
        len_y = candidate_y.shape[0]

        number_patches = min(number_patches, len_x)
        number_patches = min(number_patches, len_y)

        random_index_x = np.random.choice(len_x, number_patches, replace=False)
        random_index_y = np.random.choice(len_y, number_patches, replace=True)

        for i in range(number_patches):

            patch_x = candidate_x[random_index_x[i]]
            patch_y = candidate_y[random_index_y[i]]

            # Check if out of range
            if (patch_x + size_patch_lv_4 > slide_w_lv_4) or \
                    (patch_y + size_patch_lv_4 > slide_h_lv_4):
                continue

            # Check ratio of tumor region
            tissue_integral = integrate(integral_image_tissue, \
                                        (patch_x, patch_y), \
                                        (patch_x + size_patch_lv_4 - 1,
                                         patch_y + size_patch_lv_4 - 1))
            tissue_ratio = tissue_integral / (size_patch_lv_4**2)

            if tissue_ratio < 0.9:
                continue

            # Save patches position to csv file.
            patch_x_lv_0 = int(round(patch_x * downsample))
            patch_y_lv_0 = int(round(patch_y * downsample))
            csv_writer.writerow({'X': patch_x_lv_0, 'Y': patch_y_lv_0})
            patch_cnt += 1

            # save cut patches
            im = slide.read_region((patch_x_lv_0, patch_y_lv_0), 0,
                                   (size_patch, size_patch))
            im_rgba = np.array(im)
            im_rgb = cv2.cvtColor(im_rgba, cv2.COLOR_RGBA2RGB)
            cur_patient_name = file_path_tif.split('/')[4]
            cur_patient_name = cur_patient_name.split('.')[0]
            global ID
            cur_cut_name = save_cut_path_positive_patch_17 + cur_patient_name + '_' + str(
                ID) + '.jpg'
            ID += 1
            print('cur_cut_name', cur_cut_name)
            cv2.imwrite(cur_cut_name, im_rgb)

            # Draw patch position (color : Green)
            cv2.rectangle(wsi_jpg_visualizing_patch_position, \
                          (patch_x, patch_y), \
                          (patch_x + size_patch_lv_4, patch_y + size_patch_lv_4), \
                          (0, 255, 0), \
                          thickness=1)

    print('slide    :\t', file_path_tif)
    print('patch_cnt:\t', patch_cnt)

    # Save visualizing image.
    cv2.imwrite(save_location_path_patch_position_visualize, \
                wsi_jpg_visualizing_patch_position)

    csv_file.close()
예제 #51
0
 def __init__(self, ndpi_path):
     self.ndpi_slide = OpenSlide(ndpi_path)
예제 #52
0
def tile(path_to_slide="../Neutrophil/",
         image_file="ImageCollection_0000026280_2016-10-27 14_13_01.scn",
         outdir="../Neutrophil/Outputs/"):
    slide = OpenSlide(path_to_slide + image_file)

    assert 'openslide.bounds-height' in slide.properties
    assert 'openslide.bounds-width' in slide.properties
    assert 'openslide.bounds-x' in slide.properties
    assert 'openslide.bounds-y' in slide.properties

    x = int(slide.properties['openslide.bounds-x'])
    y = int(slide.properties['openslide.bounds-y'])
    bounds_height = int(slide.properties['openslide.bounds-height'])
    bounds_width = int(slide.properties['openslide.bounds-width'])

    half_width_region = 49
    full_width_region = 299
    stepsize = full_width_region - half_width_region

    n_x = int((bounds_width - 1) / stepsize)
    n_y = int((bounds_height - 1) / stepsize)

    dat = np.empty((0, int(299**2 * 3)), dtype='uint8')

    imloc = []
    counter = 0
    svcounter = 0
    ct = 0

    if not os.path.exists(outdir):
        os.makedirs(outdir)

    if not os.path.exists(outdir + '/Tiles'):
        os.makedirs(outdir + '/Tiles')

    if not os.path.exists(outdir + '/data'):
        os.makedirs(outdir + '/data')

    for i in range(n_x - 1):
        for j in range(n_y - 1):
            target_x = stepsize * i
            target_y = stepsize * j

            image_x = target_x + x
            image_y = target_y + y

            the_image = slide.read_region(
                (image_x, image_y), 0, (full_width_region, full_width_region))
            the_imagea = np.array(the_image)[:, :, :3]

            mask = (the_imagea[:, :, :3] > 200).astype(np.uint8)
            mask = mask[:, :, 0] * mask[:, :, 1] * mask[:, :, 2]
            white = np.sum(mask) / (299 * 299)

            if white < 0.5:
                # the_image.save(outdir + "Tiles/region_x-{}-y-{}.png".format(target_x, target_y))
                imloc.append([svcounter, counter, target_x, target_y])
                if svcounter % 5000 == 0 and svcounter != 0:
                    ct = int(svcounter / 5000)
                    np.savetxt(outdir + '/data/data-{}.txt'.format(ct),
                               dat,
                               fmt='%i',
                               delimiter='\t')
                    dat = np.empty((0, int(299**2 * 3)), dtype='uint8')
                pix = np.array(the_image)[:, :, 0:3]
                dat = np.vstack([dat, pix.flatten()])
                svcounter += 1
            else:
                pass
                # print('Ignore white!')

            counter += 1
    ct += 1
    np.savetxt(outdir + '/data/data-{}.txt'.format(ct),
               dat,
               fmt='%i',
               delimiter='\t')
    dat = np.empty((0, int(299**2 * 3)), dtype='uint8')
    imlocpd = pd.DataFrame(imloc, columns=["Num", "Count", "X", "Y"])
    imlocpd.to_csv(outdir + "/data/dict.csv", index=False)
예제 #53
0
파일: find_rois.py 프로젝트: trigrass2/Note
class WSI(object):
    """
        # ================================
        # Class to annotate WSIs with ROIs
        # ================================

    """
    index = 0
    wsi_paths = []
    mask_paths = []
    def_level = 7
    key = 0

    def read_normal_wsi(self, wsi_path):
        """
            # =====================================================================================
            # read WSI image and resize
            # Due to memory constraint, we use down sampled (4th level, 1/32 resolution) image
            # ======================================================================================
        """
        try:
            self.wsi_path = wsi_path
            self.wsi_image = OpenSlide(wsi_path)

            level = min(self.def_level, self.wsi_image.level_count - 1)
            print('level used: %d' % level)
            print(self.wsi_image.level_dimensions[level])

            self.rgb_image_pil = self.wsi_image.read_region((0, 0), level,
                                                            self.wsi_image.level_dimensions[level])
            self.rgb_image = np.array(self.rgb_image_pil)

        except OpenSlideUnsupportedFormatError:
            print('Exception: OpenSlideUnsupportedFormatError')
            return False

        return True

    def read_tumor_wsi(self, wsi_path, mask_path):
        """
            # =====================================================================================
            # read WSI image and resize
            # Due to memory constraint, we use down sampled (4th level, 1/32 resolution) image
            # ======================================================================================
        """
        try:
            self.wsi_path = wsi_path
            self.wsi_image = OpenSlide(wsi_path)
            self.mask_image = OpenSlide(mask_path)

            level_used = self.wsi_image.level_count - 1

            self.rgb_image_pil = self.wsi_image.read_region((0, 0), level_used,
                                                            self.wsi_image.level_dimensions[level_used])
            self.rgb_image = np.array(self.rgb_image_pil)

            mask_level = self.mask_image.level_count - 1
            self.rgb_mask_pil = self.mask_image.read_region((0, 0), mask_level,
                                                            self.mask_image.level_dimensions[mask_level])

            resize_factor = float(1.0 / pow(2, level_used - mask_level))
            self.mask = cv2.resize(np.array(self.rgb_mask_pil), (0, 0), fx=resize_factor, fy=resize_factor)
            # self.rgb_image = cv2.resize(self.rgb_image, (0, 0), fx=0.50, fy=0.50)
        except OpenSlideUnsupportedFormatError:
            print('Exception: OpenSlideUnsupportedFormatError')
            return False

        return True

    def find_roi_normal(self):
        # self.mask = cv2.cvtColor(self.mask, cv2.CV_32SC1)
        hsv = cv2.cvtColor(self.rgb_image, cv2.COLOR_BGR2HSV)
        # [20, 20, 20]
        lower_red = np.array([30, 30, 30])
        # [255, 255, 255]
        upper_red = np.array([200, 200, 200])
        mask = cv2.inRange(hsv, lower_red, upper_red)
        res = cv2.bitwise_and(self.rgb_image, self.rgb_image, mask=mask)

        # (50, 50)
        close_kernel = np.ones((50, 50), dtype=np.uint8)
        close_kernel_tmp = np.ones((30, 30), dtype=np.uint8)
        image_close = Image.fromarray(cv2.morphologyEx(np.array(mask), cv2.MORPH_CLOSE, close_kernel))
        image_close_tmp = Image.fromarray(cv2.morphologyEx(np.array(mask), cv2.MORPH_CLOSE, close_kernel_tmp))
        # (30, 30)
        open_kernel = np.ones((30, 30), dtype=np.uint8)
        open_kernel_tmp = np.ones((30, 30), dtype=np.uint8)
        image_open = Image.fromarray(cv2.morphologyEx(np.array(image_close), cv2.MORPH_OPEN, open_kernel))
        image_open_tmp = Image.fromarray(cv2.morphologyEx(np.array(image_close_tmp), cv2.MORPH_OPEN, open_kernel_tmp))
        contour_rgb, bounding_boxes, contour_rgb_tmp = self.get_normal_image_contours(np.array(image_open),
                                                                                      self.rgb_image,
                                                                                      np.array(image_open_tmp))
        # self.draw_bbox(bounding_boxes)

        self.display(contour_rgb, contour_rgb_tmp)

    def find_roi_tumor(self):
        # self.mask = cv2.cvtColor(self.mask, cv2.CV_32SC1)
        hsv = cv2.cvtColor(self.rgb_image, cv2.COLOR_BGR2HSV)
        lower_red = np.array([20, 20, 20])
        upper_red = np.array([200, 200, 200])
        mask = cv2.inRange(hsv, lower_red, upper_red)
        res = cv2.bitwise_and(self.rgb_image, self.rgb_image, mask=mask)

        # (50, 50)
        close_kernel = np.ones((20, 20), dtype=np.uint8)
        close_kernel_tmp = np.ones((50, 50), dtype=np.uint8)
        image_close = Image.fromarray(cv2.morphologyEx(np.array(mask), cv2.MORPH_CLOSE, close_kernel))
        image_close_tmp = Image.fromarray(cv2.morphologyEx(np.array(mask), cv2.MORPH_CLOSE, close_kernel_tmp))
        # (30, 30)
        open_kernel = np.ones((5, 5), dtype=np.uint8)
        open_kernel_tmp = np.ones((30, 30), dtype=np.uint8)
        image_open = Image.fromarray(cv2.morphologyEx(np.array(image_close), cv2.MORPH_OPEN, open_kernel))
        image_open_tmp = Image.fromarray(cv2.morphologyEx(np.array(image_close_tmp), cv2.MORPH_OPEN, open_kernel_tmp))
        contour_rgb, contour_mask, bounding_boxes, contour_rgb_tmp, contour_mask_tmp = self.get_tumor_image_contours(
            np.array(image_open), self.rgb_image,
            self.mask, np.array(image_open_tmp))

        wsi_name = utils.get_filename_from_path(self.wsi_path)
        # cv2.imwrite(os.path.join(utils.THESIS_FIGURE_DIR, wsi_name) + '_hsv_mask.png', mask)
        # cv2.imwrite(os.path.join(utils.THESIS_FIGURE_DIR, wsi_name) + '_mask.png', self.mask)
        # cv2.imwrite(os.path.join(utils.THESIS_FIGURE_DIR, wsi_name) + '_image_close.png', np.array(image_close))
        # cv2.imwrite(os.path.join(utils.THESIS_FIGURE_DIR, wsi_name) + '_image_open.png', np.array(image_open))

        # rgb_bbox = self.rgb_image.copy()
        # for i, bounding_box in enumerate(bounding_boxes):
        #     x = int(bounding_box[0])
        #     y = int(bounding_box[1])
        #     cv2.rectangle(rgb_bbox, (x, y), (x + bounding_box[2], y + bounding_box[3]), color=(0, 0, 255),
        #                   thickness=2)

        # cv2.imshow('contour_rgb', contour_rgb)
        # cv2.imshow('contour_bbox', rgb_bbox)
        # cv2.imwrite(os.path.join(utils.THESIS_FIGURE_DIR, wsi_name) + 'contour.png', contour_rgb)
        # cv2.imwrite(os.path.join(utils.THESIS_FIGURE_DIR, wsi_name) + '_bbox.png', rgb_bbox)
        cv2.imwrite(os.path.join(utils.THESIS_FIGURE_DIR, wsi_name) + '_hsv.png', hsv)
        cv2.imshow('hsv', hsv)
        cv2.waitKey(0)

        # self.display(contour_rgb, contour_rgb_tmp, contour_mask)

    def get_normal_image_contours(self, cont_img, rgb_image, cont_img_tmp):
        _, contours, _ = cv2.findContours(cont_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        _, contours_tmp, _ = cv2.findContours(cont_img_tmp, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        # print(contours)
        boundingBoxes = [cv2.boundingRect(c) for c in contours]
        # print(boundingBoxes)
        contours_rgb_image_array = np.array(rgb_image)
        contours_rgb_image_array_tmp = np.array(rgb_image)

        line_color = (255, 0, 0)  # blue color code
        cv2.drawContours(contours_rgb_image_array, contours, -1, line_color, 3)
        cv2.drawContours(contours_rgb_image_array_tmp, contours_tmp, -1, line_color, 3)
        # cv2.drawContours(mask_image, contours_mask, -1, line_color, 3)
        return contours_rgb_image_array, boundingBoxes, contours_rgb_image_array_tmp

    def get_tumor_image_contours(self, cont_img, rgb_image, mask_image, cont_img_tmp):
        _, contours, _ = cv2.findContours(cont_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        _, contours_tmp, _ = cv2.findContours(cont_img_tmp, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        # _, contours_mask, _ = cv2.findContours(mask_image, cv2.RETR_FLOODFILL, cv2.CHAIN_APPROX_SIMPLE)
        # print(contours)
        boundingBoxes = [cv2.boundingRect(c) for c in contours]
        # print(boundingBoxes)
        contours_rgb_image_array = np.array(rgb_image)
        contours_rgb_image_array_tmp = np.array(rgb_image)
        contours_mask_image_array = np.array(mask_image)
        contours_mask_image_array_tmp = np.array(mask_image)

        line_color = (255, 0, 0)  # blue color code
        cv2.drawContours(contours_rgb_image_array, contours, -1, line_color, 3)
        cv2.drawContours(contours_rgb_image_array_tmp, contours_tmp, -1, line_color, 3)
        cv2.drawContours(contours_mask_image_array, contours, -1, line_color, 3)
        cv2.drawContours(contours_mask_image_array_tmp, contours_tmp, -1, line_color, 3)
        # cv2.drawContours(mask_image, contours_mask, -1, line_color, 3)
        return contours_rgb_image_array, contours_mask_image_array, boundingBoxes, contours_rgb_image_array_tmp, \
               contours_mask_image_array_tmp

    def display(self, contour_rgb, contour_rgb_tmp, contour_mask=None):
        # cv2.imshow('rgb', self.rgb_image)
        # cv2.imshow('mask', mask)
        # cv2.imshow('image_close',np.array(image_close))
        # cv2.imshow('image_open', np.array(image_open))

        contour_rgb = cv2.resize(contour_rgb, (0, 0), fx=0.60, fy=0.60)
        cv2.imshow('contour_rgb', np.array(contour_rgb))
        contour_rgb_tmp = cv2.resize(contour_rgb_tmp, (0, 0), fx=0.60, fy=0.60)
        cv2.imshow('contour_rgb_tmp', np.array(contour_rgb_tmp))
        if contour_mask is not None:
            contour_mask = cv2.resize(contour_mask, (0, 0), fx=0.60, fy=0.60)
            cv2.imshow('contour_mask', np.array(contour_mask))

        # contour_mask_tmp = cv2.resize(contour_mask_tmp, (0, 0), fx=0.40, fy=0.40)
        # cv2.imshow('contour_mask_tmp', np.array(contour_mask_tmp))
        # cv2.imshow('contour_mask_only', np.array(contour_mask_only))
        # cv2.imshow('wsi_mask', self.mask)
        # cv2.imshow('self_bb', np.array(self.rgb_image_pil))

    def draw_bbox(self, bounding_boxes):
        draw = ImageDraw.Draw(self.rgb_image_pil)
        for i, bounding_box in enumerate(bounding_boxes):
            x = int(bounding_box[0])
            y = int(bounding_box[1])
            thickness = 5
            for offset in range(thickness):
                draw.rectangle([x + offset, y + offset, x + offset + bounding_box[2], y + offset + bounding_box[3]],
                               outline=(255, 0, 0))

    def wait(self):
        self.key = cv2.waitKey(0) & 0xFF
        print('key: %d' % self.key)

        if self.key == 27:  # escape
            return False
        elif self.key == 81:  # <- (prev)
            self.index -= 1
            if self.index < 0:
                self.index = len(self.wsi_paths) - 1
        elif self.key == 83:  # -> (next)
            self.index += 1
            if self.index >= len(self.wsi_paths):
                self.index = 0

        return True
예제 #54
0
class QtCustomWindow( qt.QWidget ):
    def __init__( self, parent = None ) :
        qt.QWidget.__init__( self, parent )
        self.current_x=0
        self.current_y=0
        #read region always works in the level 0 reference for reading locations
        self.current_zoom=0
        self.image_width=750
        self.image_height=750
        self.setWindowTitle('Red Rock')
        self.hbox = qt.QHBoxLayout(self)
        self.lbl = qt.QLabel(self)
        self.setLayout(self.hbox)
        self.initUI()
    def initUI(self):      
        # initialize the widget, make the openslide object pointing to the
        # multilevel image and initialize the view to the top left corner
        
        archivo=u'/home/martin/Downloads/CMU-1-JP2K-33005.svs'
        # openSlide object
        self.osr = OS(archivo)
        self.level_count = self.osr.level_count
        self.current_x=0
        self.current_y=0
        self.current_zoom=self.level_count-1
        self.level_dimensions=self.osr.level_dimensions
        print self.level_dimensions
        print self.osr.level_downsamples
        #width, height = osr.dimensions

        

        

        self.hbox.addWidget(self.lbl)
        
        
        #self.move(300, 200)

        
        self.updatePixmap()
        self.show()
    def updatePixmap(self):
        im=self.osr.read_region((self.current_x,self.current_y),self.current_zoom,(self.image_width,self.image_height))
        
        data = im.tostring('raw', 'RGBA')
        image = qt.QImage(data, im.size[0], im.size[1], qt.QImage.Format_ARGB32)
        pix = qt.QPixmap.fromImage(image)
        self.lbl.setPixmap(pix)
        self.lbl.show()      
    def keyPressEvent( self, event ) :
        key = event.text()
        #larger steps for zoomed out images
        step =int(64*self.osr.level_downsamples[self.current_zoom])
        print type(step)
        print type(self.current_x)
        if key=="s":
            
            self.current_y += step 
            print type(self.current_y)
            self.current_y = min(self.current_y,int(
                self.level_dimensions[0][1]-self.image_height*self.osr.level_downsamples[self.current_zoom]))
        elif key=="w":
            #larger steps for zoomed out images
            self.current_y -= step
            self.current_y = max(0, self.current_y)
        elif key=="a":
            #larger steps for zoomed out images
            self.current_x -= step
            self.current_x = max(0, self.current_x)
        elif key=="d":
            #larger steps for zoomed out images
            self.current_x += step
            self.current_x = min(self.current_x,int(
                self.level_dimensions[0][0]-self.image_width*self.osr.level_downsamples[self.current_zoom]))
        elif key=="q":
            new_zoom = min(self.current_zoom+1,self.level_count-1)
            self.updateCorner(new_zoom)
            self.current_zoom=new_zoom
        elif key=="e":
            new_zoom = max(self.current_zoom-1,0)
            self.updateCorner(new_zoom)
            self.current_zoom=new_zoom
        print "x: %s" % self.current_x
        print "y: %s" % self.current_y
        print "zoom: %s" % self.current_zoom
        self.updatePixmap()
    def updateCorner(self,new_zoom):
        #updates the current_x and current_y values to preserve the image center
        #while zooming
        self.current_x=int(self.current_x + self.image_width /2 *(self.osr.level_downsamples[self.current_zoom]-self.osr.level_downsamples[new_zoom]))
        self.current_y=int(self.current_y + self.image_height /2 *(self.osr.level_downsamples[self.current_zoom]-self.osr.level_downsamples[new_zoom]))