Beispiel #1
0
    def find_spots(self, min_spot_size=2, max_spot_size=100):
        from dials.algorithms.spot_finding.threshold import XDSThresholdStrategy
        from dials.model.data import PixelList
        from dials.model.data import PixelListLabeller

        image = self.raw_data
        mask = self.imageset.get_mask(0)[0]

        threshold_image = XDSThresholdStrategy()

        threshold_mask = threshold_image(image, mask)
        plist = PixelList(0, image, threshold_mask)

        pixel_labeller = PixelListLabeller()
        pixel_labeller.add(plist)

        creator = flex.PixelListShoeboxCreator(pixel_labeller, 0, 0, True,
                                               min_spot_size, max_spot_size,
                                               False)
        shoeboxes = creator.result()

        # turns out we need to manually filter the list to get a sensible answer
        size = creator.spot_size()
        big = size > max_spot_size
        small = size < min_spot_size
        bad = big | small
        shoeboxes = shoeboxes.select(~bad)

        centroid = shoeboxes.centroid_valid()
        intensity = shoeboxes.summed_intensity()
        observed = flex.observation(shoeboxes.panels(), centroid, intensity)

        reflections = flex.reflection_table(observed, shoeboxes)
        return reflections
def refls_from_sims(panel_imgs, detector, beam, thresh=0, filter=None, **kwargs ):
    """
    gets a reflection table from simulated panels
    :param panel_imgs: list of numpy arrays , each array is a simulated panel image
    :param detector: dxtbx detector, can have multiple nodes
    :param beam: dxtbx beam
    :param thresh: threshol
    :param filter:
    :param kwargs:
    :return: reflection table, with id coloumn set to 0
    """
    pxlst_labs = []
    for i in range(len(detector)):
        plab = PixelListLabeller()
        img = panel_imgs[i]
        if filter is not None:
            mask = filter(img, **kwargs) > thresh
        else:
            mask = img > thresh
        pl = PixelList(0, flex.double(img), flex.bool(mask))
        plab.add(pl)

        pxlst_labs.append( plab)

    pixlst_to_reftbl = PixelListToReflectionTable(
        min_spot_size=1,
        max_spot_size=194*184,
        filter_spots=FilterRunner(),
        write_hot_pixel_mask=False)

    dblock = datablock_from_numpyarrays( panel_imgs, detector, beam)
    iset = dblock.extract_imagesets()[0]
    refls = pixlst_to_reftbl(iset, pxlst_labs)[0]
    refls['id'] = flex.int(len(refls),0)
    return refls
def find_spots(image, mask, min_spot_size=1, max_spot_size=1000):
    from dials.algorithms.spot_finding.threshold import XDSThresholdStrategy
    from dials.model.data import PixelList
    from dials.model.data import PixelListLabeller

    threshold_image = XDSThresholdStrategy()

    threshold_mask = threshold_image(image, mask)
    plist = PixelList(0, image, threshold_mask)

    pixel_labeller = PixelListLabeller()

    pixel_labeller.add(plist)

    creator = flex.PixelListShoeboxCreator(
        pixel_labeller,
        0,  # panel
        0,  # zrange
        True,  # twod
        min_spot_size,  # min_pixels
        max_spot_size,  # max_pixels
        False,
    )
    shoeboxes = creator.result()

    centroid = shoeboxes.centroid_valid()
    intensity = shoeboxes.summed_intensity()
    observed = flex.observation(shoeboxes.panels(), centroid, intensity)

    return flex.reflection_table(observed, shoeboxes)
Beispiel #4
0
    def find_spots(self, min_spot_size=2, max_spot_size=100):
        """
        Find the strong spots on the image

        """
        from dials.algorithms.spot_finding.threshold import DispersionThresholdStrategy
        from dials.model.data import PixelList
        from dials.model.data import PixelListLabeller
        from dials.array_family import flex

        print("")
        print("-" * 80)
        print(" Finding strong spots")
        print("-" * 80)
        print("")

        # Instantiate the threshold function
        threshold = DispersionThresholdStrategy()

        # Get the raw data and image mask
        image = self.experiment.imageset.get_raw_data(0)[0]
        mask = self.experiment.imageset.get_mask(0)[0]

        # Threshold the image and create the pixel labeller
        threshold_mask = threshold(image, mask)
        pixel_labeller = PixelListLabeller()
        pixel_labeller.add(PixelList(0, image, threshold_mask))

        # Create the shoebox list from the pixel list
        creator = flex.PixelListShoeboxCreator(
            pixel_labeller,
            0,  # Panel number
            0,  # Z start
            True,  # 2D
            self.params.spot_finding.min_spot_size,  # Min Pixels
            self.params.spot_finding.max_spot_size,  # Max Pixels
            False,
        )  # Find hot pixels
        shoeboxes = creator.result()

        # Filter the list to remove large and small spots
        size = creator.spot_size()
        large = size > self.params.spot_finding.max_spot_size
        small = size < self.params.spot_finding.min_spot_size
        bad = large | small
        shoeboxes = shoeboxes.select(~bad)
        print("Discarding %d spots with < %d pixels" %
              (small.count(True), self.params.spot_finding.min_spot_size))
        print("Discarding %d spots with > %d pixels" %
              (large.count(True), self.params.spot_finding.max_spot_size))

        # Extract the strong spot information
        centroid = shoeboxes.centroid_valid()
        intensity = shoeboxes.summed_intensity()
        observed = flex.observation(shoeboxes.panels(), centroid, intensity)

        # Create the reflection list
        self.reflections = flex.reflection_table(observed, shoeboxes)
        print("Using %d strong spots" % len(self.reflections))
Beispiel #5
0
    def __call__(self, index):
        """
        Extract strong pixels from an image

        :param index: The index of the image
        """
        from dials.model.data import PixelListLabeller

        # Initialise the pixel labeller
        num_panels = len(self.imageset.get_detector())
        pixel_labeller = [PixelListLabeller() for p in range(num_panels)]

        # Call the super function
        result = super(ExtractPixelsFromImage2DNoShoeboxes,
                       self).__call__(index)

        # Add pixel lists to the labeller
        assert len(pixel_labeller) == len(
            result.pixel_list), "Inconsistent size"
        for plabeller, plist in zip(pixel_labeller, result.pixel_list):
            plabeller.add(plist)

        # Create shoeboxes from pixel list
        converter = PixelListToReflectionTable(self.min_spot_size,
                                               self.max_spot_size,
                                               self.filter_spots, False)
        reflections, _ = converter(self.imageset, pixel_labeller)

        # Delete the shoeboxes
        del reflections["shoeboxes"]

        # Return the reflections
        return [reflections]
Beispiel #6
0
    def __call__(self, index):
        """
        Extract strong pixels from an image

        :param index: The index of the image
        """
        # Initialise the pixel labeller
        num_panels = len(self.imageset.get_detector())
        pixel_labeller = [PixelListLabeller() for p in range(num_panels)]

        # Call the super function
        result = super().__call__(index)

        # Add pixel lists to the labeller
        assert len(pixel_labeller) == len(result), "Inconsistent size"
        for plabeller, plist in zip(pixel_labeller, result):
            plabeller.add(plist)

        # Create shoeboxes from pixel list
        reflections, _ = pixel_list_to_reflection_table(
            self.imageset,
            pixel_labeller,
            filter_spots=self.filter_spots,
            min_spot_size=self.min_spot_size,
            max_spot_size=self.max_spot_size,
            write_hot_pixel_mask=False,
        )

        # Delete the shoeboxes
        del reflections["shoeboxes"]

        # Return the reflections
        return [reflections]
Beispiel #7
0
def test_add_image():
    from dials.model.data import PixelList, PixelListLabeller
    from scitbx.array_family import flex
    size = (2000, 2000)
    sf = 10
    labeller = PixelListLabeller()

    count = 0
    for i in range(3):
        image = flex.random_int_gaussian_distribution(size[0] * size[1], 100,
                                                      5)
        mask = flex.random_bool(size[0] * size[1], 0.5)
        image.reshape(flex.grid(size))
        mask.reshape(flex.grid(size))
        pl = PixelList(sf + i, image, mask)
        count += len(mask.as_1d().select(mask.as_1d()))
        labeller.add(pl)
    assert len(labeller.values()) == count
Beispiel #8
0
def find_spots(image):
    from dials.algorithms.spot_finding.threshold import DispersionThresholdStrategy
    from dials.model.data import PixelList
    from dials.model.data import PixelListLabeller

    thresholder = DispersionThresholdStrategy(gain=1)
    mask = image.as_1d() >= 0  # flex.bool(image.size(), True)
    mask.reshape(flex.grid(*image.focus()))

    threshold_mask = thresholder(image, mask=mask)
    plist = PixelList(0, image, threshold_mask)

    pixel_labeller = PixelListLabeller()
    pixel_labeller.add(plist)

    creator = flex.PixelListShoeboxCreator(pixel_labeller, 0, 0, True, 2, 100,
                                           False)
    shoeboxes = creator.result()
    return shoeboxes
Beispiel #9
0
def image_to_shoeboxes(image):
    """For a given image, find spots 2 - 100 pixels im size, assuming a gain
    of 1, return the list of spot shoeboxes. Also assumes valid intensities in
    range 0...N."""

    thresholder = DispersionThresholdStrategy(gain=1)

    mask = image.as_1d() >= 0
    mask.reshape(flex.grid(*image.focus()))

    threshold_mask = thresholder(image, mask=mask)
    plist = PixelList(0, image, threshold_mask)

    pixel_labeller = PixelListLabeller()
    pixel_labeller.add(plist)

    creator = flex.PixelListShoeboxCreator(pixel_labeller, 0, 0, True, 2, 100,
                                           False)
    shoeboxes = creator.result()
    return shoeboxes
Beispiel #10
0
    def tst_with_no_points(self):

        from dials.model.data import PixelList, PixelListLabeller
        from scitbx.array_family import flex
        size = (500, 500)
        sf = 0
        labeller = PixelListLabeller()

        count = 0
        mask_list = []
        for i in range(3):
            image = flex.random_int_gaussian_distribution(
                size[0] * size[1], 100, 5)
            mask = flex.bool(size[0] * size[0], False)
            image.reshape(flex.grid(size))
            mask.reshape(flex.grid(size))
            pl = PixelList(sf + i, image, mask)
            count += len(mask.as_1d().select(mask.as_1d()))
            labeller.add(pl)
            mask_list.append(mask)

        coords = labeller.coords()
        labels1 = labeller.labels_2d()
        labels2 = labeller.labels_2d()

        assert len(coords) == 0
        assert len(labels1) == 0
        assert len(labels2) == 0

        print 'OK'
Beispiel #11
0
def find(greyscale_flex, params, mask=None):
    '''Find stars on input greyscale flex image.'''

    from dials.algorithms.spot_finding.threshold import \
        DispersionThresholdStrategy
    from dials.model.data import PixelList
    from dials.model.data import PixelListLabeller
    from dials.array_family import flex

    thresholder = DispersionThresholdStrategy(gain=params.gain)
    if not mask:
        mask = flex.bool(greyscale_flex.size(), True)
    mask.reshape(flex.grid(*greyscale_flex.focus()))

    threshold_mask = thresholder(greyscale_flex, mask=mask)
    plist = PixelList(0, greyscale_flex, threshold_mask)

    pixel_labeller = PixelListLabeller()
    pixel_labeller.add(plist)

    creator = flex.PixelListShoeboxCreator(pixel_labeller, 0, 0, True,
                                           params.min_size, params.max_size,
                                           False)
    shoeboxes = creator.result()

    # remove nonsense
    size = creator.spot_size()
    big = size > params.max_size
    small = size < params.min_size
    bad = big | small
    shoeboxes = shoeboxes.select(~bad)

    centroid = shoeboxes.centroid_valid()
    intensity = shoeboxes.summed_intensity()
    observed = flex.observation(shoeboxes.panels(), centroid, intensity)

    stars = flex.reflection_table(observed, shoeboxes)
    return stars
Beispiel #12
0
    def tst_labels_3d(self):
        from dials.model.data import PixelList, PixelListLabeller
        from scitbx.array_family import flex
        size = (500, 500)
        sf = 0
        labeller = PixelListLabeller()

        count = 0
        mask_list = []
        for i in range(3):
            image = flex.random_int_gaussian_distribution(
                size[0] * size[1], 100, 5)
            mask = flex.random_bool(size[0] * size[1], 0.5)
            image.reshape(flex.grid(size))
            mask.reshape(flex.grid(size))
            pl = PixelList(sf + i, image, mask)
            count += len(mask.as_1d().select(mask.as_1d()))
            labeller.add(pl)
            mask_list.append(mask)

        coords = labeller.coords()
        labels = labeller.labels_3d()

        # Create a map of labels
        label_map = flex.int(flex.grid(3, size[0], size[1]))
        for c, l in zip(coords, labels):
            label_map[c] = l

        # Ensure all labels are correct
        vi = 0
        for k in range(3):
            for j in range(size[0]):
                for i in range(size[1]):
                    if mask_list[k][j, i]:

                        l1 = labels[vi]
                        if k > 0 and mask_list[k - 1][j, i]:
                            l2 = label_map[k - 1, j, i]
                            assert (l2 == l1)
                        if j > 0 and mask_list[k][j - 1, i]:
                            l2 = label_map[k, j - 1, i]
                            assert (l2 == l1)
                        if i > 0 and mask_list[k][j, i - 1]:
                            l2 = label_map[k, j, i - 1]
                            assert (l2 == l1)
                        vi += 1

        # Test passed
        print 'OK'
Beispiel #13
0
    def _find_spots(self, imageset):
        """
        Find the spots in the imageset

        :param imageset: The imageset to process
        :return: The list of spot shoeboxes
        """
        from dials.model.data import PixelListLabeller
        from dials.util.mp import batch_multi_node_parallel_map

        # Change the number of processors if necessary
        mp_nproc = self.mp_nproc
        mp_njobs = self.mp_njobs
        if os.name == "nt" and (mp_nproc > 1 or mp_njobs > 1):
            logger.warning(_no_multiprocessing_on_windows)
            mp_nproc = 1
            mp_njobs = 1
        if mp_nproc * mp_njobs > len(imageset):
            mp_nproc = min(mp_nproc, len(imageset))
            mp_njobs = int(math.ceil(len(imageset) / mp_nproc))

        mp_method = self.mp_method
        mp_chunksize = self.mp_chunksize

        if mp_chunksize == libtbx.Auto:
            mp_chunksize = self._compute_chunksize(len(imageset),
                                                   mp_njobs * mp_nproc,
                                                   self.min_chunksize)
            logger.info("Setting chunksize=%i" % mp_chunksize)

        len_by_nproc = int(math.floor(len(imageset) / (mp_njobs * mp_nproc)))
        if mp_chunksize > len_by_nproc:
            mp_chunksize = len_by_nproc
        if mp_chunksize == 0:
            mp_chunksize = 1
        assert mp_nproc > 0, "Invalid number of processors"
        assert mp_njobs > 0, "Invalid number of jobs"
        assert mp_njobs == 1 or mp_method is not None, "Invalid cluster method"
        assert mp_chunksize > 0, "Invalid chunk size"

        # The extract pixels function
        function = ExtractPixelsFromImage(
            imageset=imageset,
            threshold_function=self.threshold_function,
            mask=self.mask,
            max_strong_pixel_fraction=self.max_strong_pixel_fraction,
            compute_mean_background=self.compute_mean_background,
            region_of_interest=self.region_of_interest,
        )

        # The indices to iterate over
        indices = list(range(len(imageset)))

        # Initialise the pixel labeller
        num_panels = len(imageset.get_detector())
        pixel_labeller = [PixelListLabeller() for p in range(num_panels)]

        # Do the processing
        logger.info("Extracting strong pixels from images")
        if mp_njobs > 1:
            logger.info(
                " Using %s with %d parallel job(s) and %d processes per node\n"
                % (mp_method, mp_njobs, mp_nproc))
        else:
            logger.info(" Using multiprocessing with %d parallel job(s)\n" %
                        (mp_nproc))
        if mp_nproc > 1 or mp_njobs > 1:

            def process_output(result):
                for message in result[1]:
                    logger.log(message.levelno, message.msg)
                assert len(pixel_labeller) == len(
                    result[0].pixel_list), "Inconsistent size"
                for plabeller, plist in zip(pixel_labeller,
                                            result[0].pixel_list):
                    plabeller.add(plist)
                result[0].pixel_list = None

            batch_multi_node_parallel_map(
                func=ExtractSpotsParallelTask(function),
                iterable=indices,
                nproc=mp_nproc,
                njobs=mp_njobs,
                cluster_method=mp_method,
                chunksize=mp_chunksize,
                callback=process_output,
            )
        else:
            for task in indices:
                result = function(task)
                assert len(pixel_labeller) == len(
                    result.pixel_list), "Inconsistent size"
                for plabeller, plist in zip(pixel_labeller, result.pixel_list):
                    plabeller.add(plist)
                    result.pixel_list = None

        # Create shoeboxes from pixel list
        converter = PixelListToReflectionTable(
            self.min_spot_size,
            self.max_spot_size,
            self.filter_spots,
            self.write_hot_pixel_mask,
        )
        return converter(imageset, pixel_labeller)
Beispiel #14
0
def refls_from_sims(panel_imgs,
                    detector,
                    beam,
                    thresh=0,
                    filter=None,
                    panel_ids=None,
                    **kwargs):
    """
    This class is for converting the centroids in the noiseless simtbx images
    to a multi panel reflection table

    TODO: bring up poor documentation and consider asking the dials team
    to make a push to beter document for the sake of developers
    This function took 3 hours to figure out how to do...

    :param panel_imgs: list or 3D array of detector panel simulations
        currently supports CSPAD only (194x185 shaped panels)
    :param detector: dxtbx  detector model of a caspad
    :param beam:  dxtxb beam model
    :param thresh: threshol intensity for labeling centroids
    :param filter: optional filter to apply to images before
        labeling threshold, typically one of scipy.ndimage's filters
    :param pids: panel IDS , else assumes panel_imgs is same length as detector
    :param kwargs: kwargs to pass along to the optional filter
    :return: a reflection table of spot centroids
    """
    from dials.algorithms.spot_finding.factory import FilterRunner
    from dials.model.data import PixelListLabeller, PixelList
    from dials.algorithms.spot_finding.finder import PixelListToReflectionTable
    from cxid9114 import utils

    if panel_ids is None:
        panel_ids = np.arange(len(detector))
    pxlst_labs = []
    for i, pid in enumerate(panel_ids):
        plab = PixelListLabeller()
        img = panel_imgs[i]
        if filter is not None:
            mask = filter(img, **kwargs) > thresh
        else:
            mask = img > thresh
        img_sz = detector[pid].get_image_size()
        flex_img = flex.double(img)
        flex_img.reshape(flex.grid(img_sz))

        flex_mask = flex.bool(mask)
        flex_mask.resize(flex.grid(img_sz))
        pl = PixelList(0, flex.double(img), flex.bool(mask))
        plab.add(pl)

        pxlst_labs.append(plab)

    pixlst_to_reftbl = PixelListToReflectionTable(
        min_spot_size=1,
        max_spot_size=194 * 184,
        filter_spots=FilterRunner(),  # must use a dummie filter runner!
        write_hot_pixel_mask=False)

    dblock = utils.datablock_from_numpyarrays(panel_imgs, detector, beam)
    iset = dblock.extract_imagesets()[0]
    refls = pixlst_to_reftbl(iset, pxlst_labs)[0]

    return refls
Beispiel #15
0
    def _find_spots(self, imageset):
        """
        Find the spots in the imageset

        :param imageset: The imageset to process
        :return: The list of spot shoeboxes
        """
        # Change the number of processors if necessary
        mp_nproc = self.mp_nproc
        mp_njobs = self.mp_njobs
        if mp_nproc is libtbx.Auto:
            mp_nproc = available_cores()
            logger.info(f"Setting nproc={mp_nproc}")
        if mp_nproc * mp_njobs > len(imageset):
            mp_nproc = min(mp_nproc, len(imageset))
            mp_njobs = int(math.ceil(len(imageset) / mp_nproc))

        mp_method = self.mp_method
        mp_chunksize = self.mp_chunksize

        if mp_chunksize is libtbx.Auto:
            mp_chunksize = self._compute_chunksize(len(imageset),
                                                   mp_njobs * mp_nproc,
                                                   self.min_chunksize)
            logger.info("Setting chunksize=%i", mp_chunksize)

        len_by_nproc = int(math.floor(len(imageset) / (mp_njobs * mp_nproc)))
        if mp_chunksize > len_by_nproc:
            mp_chunksize = len_by_nproc
        if mp_chunksize == 0:
            mp_chunksize = 1
        assert mp_nproc > 0, "Invalid number of processors"
        assert mp_njobs > 0, "Invalid number of jobs"
        assert mp_njobs == 1 or mp_method is not None, "Invalid cluster method"
        assert mp_chunksize > 0, "Invalid chunk size"

        # The extract pixels function
        function = ExtractPixelsFromImage(
            imageset=imageset,
            threshold_function=self.threshold_function,
            mask=self.mask,
            max_strong_pixel_fraction=self.max_strong_pixel_fraction,
            compute_mean_background=self.compute_mean_background,
            region_of_interest=self.region_of_interest,
        )

        # The indices to iterate over
        indices = list(range(len(imageset)))

        # Initialise the pixel labeller
        num_panels = len(imageset.get_detector())
        pixel_labeller = [PixelListLabeller() for p in range(num_panels)]

        # Do the processing
        logger.info("Extracting strong pixels from images")
        if mp_njobs > 1:
            logger.info(
                " Using %s with %d parallel job(s) and %d processes per node\n",
                mp_method,
                mp_njobs,
                mp_nproc,
            )
        else:
            logger.info(" Using multiprocessing with %d parallel job(s)\n",
                        mp_nproc)
        if mp_nproc > 1 or mp_njobs > 1:

            def process_output(result):
                rehandle_cached_records(result[1])
                assert len(pixel_labeller) == len(
                    result[0]), "Inconsistent size"
                for plabeller, plist in zip(pixel_labeller, result[0]):
                    plabeller.add(plist)

            batch_multi_node_parallel_map(
                func=ExtractSpotsParallelTask(function),
                iterable=indices,
                nproc=mp_nproc,
                njobs=mp_njobs,
                cluster_method=mp_method,
                chunksize=mp_chunksize,
                callback=process_output,
            )
        else:
            for task in indices:
                result = function(task)
                assert len(pixel_labeller) == len(result), "Inconsistent size"
                for plabeller, plist in zip(pixel_labeller, result):
                    plabeller.add(plist)
                result.clear()

        # Create shoeboxes from pixel list
        return pixel_list_to_reflection_table(
            imageset,
            pixel_labeller,
            filter_spots=self.filter_spots,
            min_spot_size=self.min_spot_size,
            max_spot_size=self.max_spot_size,
            write_hot_pixel_mask=self.write_hot_pixel_mask,
        )
Beispiel #16
0
    def _find_spots(self, imageset):
        '''
    Find the spots in the imageset

    :param imageset: The imageset to process
    :return: The list of spot shoeboxes

    '''
        from dials.array_family import flex
        from dxtbx.imageset import ImageSweep
        from dials.model.data import PixelListLabeller
        from dials.util.mp import batch_multi_node_parallel_map
        from math import floor, ceil
        import platform

        # Change the number of processors if necessary
        mp_nproc = self.mp_nproc
        mp_njobs = self.mp_njobs
        if (mp_nproc > 1 or mp_njobs > 1) and platform.system(
        ) == "Windows":  # platform.system() forks which is bad for MPI, so don't use it unless nproc > 1
            logger.warn("")
            logger.warn("*" * 80)
            logger.warn(
                "Multiprocessing is not available on windows. Setting nproc = 1, njobs = 1"
            )
            logger.warn("*" * 80)
            logger.warn("")
            mp_nproc = 1
            mp_njobs = 1
        if mp_nproc * mp_njobs > len(imageset):
            mp_nproc = min(mp_nproc, len(imageset))
            mp_njobs = int(ceil(len(imageset) / mp_nproc))

        mp_method = self.mp_method
        mp_chunksize = self.mp_chunksize

        import libtbx
        if mp_chunksize == libtbx.Auto:
            mp_chunksize = self._compute_chunksize(len(imageset),
                                                   mp_njobs * mp_nproc,
                                                   self.min_chunksize)
            logger.info("Setting chunksize=%i" % mp_chunksize)

        len_by_nproc = int(floor(len(imageset) / (mp_njobs * mp_nproc)))
        if mp_chunksize > len_by_nproc:
            mp_chunksize = len_by_nproc
        if mp_chunksize == 0:
            mp_chunksize = 1
        assert mp_nproc > 0, "Invalid number of processors"
        assert mp_njobs > 0, "Invalid number of jobs"
        assert mp_njobs == 1 or mp_method is not None, "Invalid cluster method"
        assert mp_chunksize > 0, "Invalid chunk size"

        # The extract pixels function
        function = ExtractPixelsFromImage(
            imageset=imageset,
            threshold_function=self.threshold_function,
            mask=self.mask,
            max_strong_pixel_fraction=self.max_strong_pixel_fraction,
            compute_mean_background=self.compute_mean_background,
            region_of_interest=self.region_of_interest)

        # The indices to iterate over
        indices = list(range(len(imageset)))

        # Initialise the pixel labeller
        num_panels = len(imageset.get_detector())
        pixel_labeller = [PixelListLabeller() for p in range(num_panels)]

        # Do the processing
        logger.info('Extracting strong pixels from images')
        if mp_njobs > 1:
            logger.info(
                ' Using %s with %d parallel job(s) and %d processes per node\n'
                % (mp_method, mp_njobs, mp_nproc))
        else:
            logger.info(' Using multiprocessing with %d parallel job(s)\n' %
                        (mp_nproc))
        if mp_nproc > 1 or mp_njobs > 1:

            def process_output(result):
                for message in result[1]:
                    logger.log(message.levelno, message.msg)
                assert len(pixel_labeller) == len(
                    result[0].pixel_list), "Inconsistent size"
                for plabeller, plist in zip(pixel_labeller,
                                            result[0].pixel_list):
                    plabeller.add(plist)
                result[0].pixel_list = None

            batch_multi_node_parallel_map(
                func=ExtractSpotsParallelTask(function),
                iterable=indices,
                nproc=mp_nproc,
                njobs=mp_njobs,
                cluster_method=mp_method,
                chunksize=mp_chunksize,
                callback=process_output)
        else:
            for task in indices:
                result = function(task)
                assert len(pixel_labeller) == len(
                    result.pixel_list), "Inconsistent size"
                for plabeller, plist in zip(pixel_labeller, result.pixel_list):
                    plabeller.add(plist)
                    result.pixel_list = None

        # Create shoeboxes from pixel list
        converter = PixelListToReflectionTable(self.min_spot_size,
                                               self.max_spot_size,
                                               self.filter_spots,
                                               self.write_hot_pixel_mask)
        return converter(imageset, pixel_labeller)