Extract any bitonal image that we think we can improve as JBIG2
974057
def extract_images_jbig2(pike, root, log, options):
    """"""

    jbig2_groups = defaultdict(list)
    for pageno, xref, ext in extract_images(
        pike, root, log, options, extract_image_jbig2
    ):
        group = pageno // options.jbig2_page_group_size
        jbig2_groups[group].append((xref, ext))

    # Elide empty groups
    jbig2_groups = {
        group: xrefs for group, xrefs in jbig2_groups.items() if len(xrefs) > 0
    }
    log.debug("Optimizable images: JBIG2 groups: %s", (len(jbig2_groups),))
    return jbig2_groups
474477
private void getYCCArray() {
        int values[] = new int[imageWidth * imageHeight];
        int r, g, b, y, x;
// In order to minimize the chance that grabPixels will throw an exception
// it may be necessary to grab some pixels every few scanlines and process
// those before going for more.  The time expense may be prohibitive.
// However, for a situation where memory overhead is a concern, this may be
// the only choice.
        PixelGrabber grabber = new PixelGrabber(imageobj.getSource(), 0, 0, imageWidth, imageHeight, values, 0, imageWidth);
        int maxHsampFactor = 1;
        int maxVsampFactor = 1;
        for (y = 0; y < NumberOfComponents; y++) {
            maxHsampFactor = Math.max(maxHsampFactor, HsampFactor[y]);
            maxVsampFactor = Math.max(maxVsampFactor, VsampFactor[y]);
        }
        for (y = 0; y < NumberOfComponents; y++) {
            compWidth[y] = (((imageWidth % 8 != 0) ? ((int) Math.ceil((double) imageWidth / 8.0)) * 8 : imageWidth) / maxHsampFactor) * HsampFactor[y];
            if (compWidth[y] != ((imageWidth / maxHsampFactor) * HsampFactor[y])) {
                lastColumnIsDummy[y] = true;
            }
            // results in a multiple of 8 for compWidth
            // this will make the rest of the program fail for the unlikely
            // event that someone tries to compress an 16 x 16 pixel image
            // which would of course be worse than pointless
            BlockWidth[y] = (int) Math.ceil((double) compWidth[y] / 8.0);
            compHeight[y] = (((imageHeight % 8 != 0) ? ((int) Math.ceil((double) imageHeight / 8.0)) * 8 : imageHeight) / maxVsampFactor) * VsampFactor[y];
            if (compHeight[y] != ((imageHeight / maxVsampFactor) * VsampFactor[y])) {
                lastRowIsDummy[y] = true;
            }
            BlockHeight[y] = (int) Math.ceil((double) compHeight[y] / 8.0);
        }
        try {
            grabber.grabPixels();
        } catch (InterruptedException ignored) {
        }
        float Y[][] = new float[compHeight[0]][compWidth[0]];
        float Cr1[][] = new float[compHeight[0]][compWidth[0]];
        float Cb1[][] = new float[compHeight[0]][compWidth[0]];
        int index = 0;
        for (y = 0; y < imageHeight; ++y) {
            for (x = 0; x < imageWidth; ++x) {
                r = ((values[index] >> 16) & 0xff);
                g = ((values[index] >> 8) & 0xff);
                b = (values[index] & 0xff);

// The following three lines are a more correct color conversion but
// the current conversion technique is sufficient and results in a higher
// compression rate.
//                Y[y][x] = 16 + (float)(0.8588*(0.299 * (float)r + 0.587 * (float)g + 0.114 * (float)b ));
//                Cb1[y][x] = 128 + (float)(0.8784*(-0.16874 * (float)r - 0.33126 * (float)g + 0.5 * (float)b));
//                Cr1[y][x] = 128 + (float)(0.8784*(0.5 * (float)r - 0.41869 * (float)g - 0.08131 * (float)b));
                Y[y][x] = (float) ((0.299 * (float) r + 0.587 * (float) g + 0.114 * (float) b));
                Cb1[y][x] = 128 + (float) ((-0.16874 * (float) r - 0.33126 * (float) g + 0.5 * (float) b));
                Cr1[y][x] = 128 + (float) ((0.5 * (float) r - 0.41869 * (float) g - 0.08131 * (float) b));
                index++;
            }
        }

// Need a way to set the H and V sample factors before allowing downsampling.
// For now (04/04/98) downsampling must be hard coded.
// Until a better downsampler is implemented, this will not be done.
// Downsampling is currently supported.  The downsampling method here
// is a simple box filter.

        Components[0] = Y;
//        Cb2 = DownSample(Cb1, 1);
        Components[1] = Cb1;
//        Cr2 = DownSample(Cr1, 2);
        Components[2] = Cr1;
    }
88126
def cutout_source(x_pos, y_pos, image, kernelsize, shift=True):
    
    if kernelsize % 2 == 0:
        raise ValueError("even pixel number kernel size not supported!")
    x_int = int(round(x_pos))
    y_int = int(round(y_pos))
    n = len(image)
    d = (kernelsize - 1)/2
    x_max = int(np.minimum(x_int + d + 1, n))
    x_min = int(np.maximum(x_int - d, 0))
    y_max = int(np.minimum(y_int + d + 1, n))
    y_min = int(np.maximum(y_int - d, 0))
    image_cut = copy.deepcopy(image[y_min:y_max, x_min:x_max])
    shift_x = x_int - x_pos
    shift_y = y_int - y_pos
    if shift is True:
        kernel_shift = de_shift_kernel(image_cut, shift_x, shift_y, iterations=50)
    else:
        kernel_shift = image_cut
    kernel_final = np.zeros((kernelsize, kernelsize))

    k_l2_x = int((kernelsize - 1) / 2)
    k_l2_y = int((kernelsize - 1) / 2)

    xk_min = np.maximum(0, -x_int + k_l2_x)
    yk_min = np.maximum(0, -y_int + k_l2_y)
    xk_max = np.minimum(kernelsize, -x_int + k_l2_x + n)
    yk_max = np.minimum(kernelsize, -y_int + k_l2_y + n)

    kernel_final[yk_min:yk_max, xk_min:xk_max] = kernel_shift
    return kernel_final
137716
@Override
  public BitArray getBlackRow(int y, BitArray row) throws NotFoundException {
    LuminanceSource source = getLuminanceSource();
    int width = source.getWidth();
    if (row == null || row.getSize() < width) {
      row = new BitArray(width);
    } else {
      row.clear();
    }

    initArrays(width);
    byte[] localLuminances = source.getRow(y, luminances);
    int[] localBuckets = buckets;
    for (int x = 0; x < width; x++) {
      localBuckets[(localLuminances[x] & 0xff) >> LUMINANCE_SHIFT]++;
    }
    int blackPoint = estimateBlackPoint(localBuckets);

    if (width < 3) {
      // Special case for very small images
      for (int x = 0; x < width; x++) {
        if ((localLuminances[x] & 0xff) < blackPoint) {
          row.set(x);
        }
      }
    } else {
      int left = localLuminances[0] & 0xff;
      int center = localLuminances[1] & 0xff;
      for (int x = 1; x < width - 1; x++) {
        int right = localLuminances[x + 1] & 0xff;
        // A simple -1 4 -1 box filter with a weight of 2.
        if (((center * 4) - left - right) / 2 < blackPoint) {
          row.set(x);
        }
        left = center;
        center = right;
      }
    }
    return row;
  }
467473
private void extractFgBgData(Map<Integer, Integer> colorHistogram) {
        if (colorHistogram.isEmpty()) {
            // An empty histogram indicates we've encountered a 0px area image. It has no luminance.
            mBackgroundLuminance = mForegroundLuminance = 0;
            mBackgroundColor = Color.BLACK;
            mForegroundColor = Color.BLACK;
        } else if (colorHistogram.size() == 1) {
            // Deal with views that only contain a single color
            final int singleColor = colorHistogram.keySet().iterator().next();
            mBackgroundLuminance = mForegroundLuminance =
                    ContrastUtils.calculateLuminance(singleColor);
            mForegroundColor = singleColor;
            mBackgroundColor = singleColor;
        } else {
            // Find the average luminance value within the set of luminances for
            // purposes of splitting luminance values into high-luminance and
            // low-luminance buckets. This is explicitly not a weighted average.
            double luminanceSum = 0;
            for (int color : colorHistogram.keySet()) {
                luminanceSum += ContrastUtils.calculateLuminance(color);
            }

            final double averageLuminance = luminanceSum / colorHistogram.size();

            // Select the highest and lowest luminance values that contribute to
            // most number of pixels in the image -- our background and
            // foreground colors.
            double lowLuminanceContributor = 0.0d;
            double highLuminanceContributor = 1.0d;
            int lowLuminanceColor = -1;
            int highLuminanceColor = -1;
            int maxLowLuminanceFrequency = 0;
            int maxHighLuminanceFrequency = 0;
            for (Entry<Integer, Integer> entry : colorHistogram.entrySet()) {
                final int color = entry.getKey();
                final double luminanceValue = ContrastUtils.calculateLuminance(color);
                final int frequency = entry.getValue();
                if ((luminanceValue < averageLuminance) && (frequency > maxLowLuminanceFrequency)) {
                    lowLuminanceContributor = luminanceValue;
                    maxLowLuminanceFrequency = frequency;
                    lowLuminanceColor = color;
                } else if ((luminanceValue >= averageLuminance)
                        && (frequency > maxHighLuminanceFrequency)) {
                    highLuminanceContributor = luminanceValue;
                    maxHighLuminanceFrequency = frequency;
                    highLuminanceColor = color;
                }
            }

            // Background luminance is that which occurs more frequently
            if (maxHighLuminanceFrequency > maxLowLuminanceFrequency) {
                mBackgroundLuminance = highLuminanceContributor;
                mBackgroundColor = highLuminanceColor;
                mForegroundLuminance = lowLuminanceContributor;
                mForegroundColor = lowLuminanceColor;
            } else {
                mBackgroundLuminance = lowLuminanceContributor;
                mBackgroundColor = lowLuminanceColor;
                mForegroundLuminance = highLuminanceContributor;
                mForegroundColor = highLuminanceColor;
            }
        }
    }
917688
def inner(self):
        

        inner_array = nd.morphology.binary_erosion(self.bitmap)
        return Region(inner_array)
28813
private void readBitmap() {
        // (sub)image position & size.
        header.currentFrame.ix = readShort();
        header.currentFrame.iy = readShort();
        header.currentFrame.iw = readShort();
        header.currentFrame.ih = readShort();

        int packed = read();
        // 1 - local color table flag interlace
        boolean lctFlag = (packed & 0x80) != 0;
        int lctSize = (int) Math.pow(2, (packed & 0x07) + 1);
        // 3 - sort flag
        // 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color
        // table size
        header.currentFrame.interlace = (packed & 0x40) != 0;
        if (lctFlag) {
            // Read table.
            header.currentFrame.lct = readColorTable(lctSize);
        } else {
            // No local color table.
            header.currentFrame.lct = null;
        }

        // Save this as the decoding position pointer.
        header.currentFrame.bufferFrameStart = rawData.position();

        // False decode pixel data to advance buffer.
        skipImageData();

        if (err()) {
            return;
        }

        header.frameCount++;
        // Add image to frame.
        header.frames.add(header.currentFrame);
    }
1267391
def extract_content(image_path, member_name, return_hash=False):
    '''
    '''
    if member_name.startswith('./'):
        member_name = member_name.replace('.','',1)
    if return_hash:
        hashy = hashlib.md5()

    try:
        content = Client.execute(image_path,'cat %s' %(member_name))
    except:
        return None

    if not isinstance(content,bytes):
        content = content.encode('utf-8')
        content = bytes(content)

    # If permissions don't allow read, return None
    if len(content) == 0:
        return None
    if return_hash:
        hashy.update(content)
        return hashy.hexdigest()
    return content
459381
def sample_image(d, data, u, v, w, i=-1, verbose=0, imager='xy', wres=100):
    

    if i == -1:
        i = len(data)/2

    if imager == 'xy':
        image = rtlib.imgonefullxy(n.outer(u, d['freq']/d['freq_orig'][0]), n.outer(v, d['freq']/d['freq_orig'][0]), data[i], d['npixx'], d['npixy'], d['uvres'], verbose=verbose)
    elif imager == 'w':
        npix = max(d['npixx'], d['npixy'])
        bls, uvkers = rtlib.genuvkernels(w, wres, npix, d['uvres'], ksize=21, oversample=1)
        image = rtlib.imgonefullw(n.outer(u, d['freq']/d['freq_orig'][0]), n.outer(v, d['freq']/d['freq_orig'][0]), data[i], npix, d['uvres'], bls, uvkers, verbose=verbose)

#        bls, lmkers = rtlib.genlmkernels(w, wres, npix, d['uvres'])
#        image = rtlib.imgonefullw(n.outer(u, d['freq']/d['freq_orig'][0]), n.outer(v, d['freq']/d['freq_orig'][0]), data[i], npix, d['uvres'], [bls[0]], [lmkers[0]], verbose=verbose)

    return image
53406
private void decodeBitmapData(GifFrame frame) {
        workBufferSize = 0;
        workBufferPosition = 0;
        if (frame != null) {
            // Jump to the frame start position.
            rawData.position(frame.bufferFrameStart);
        }

        int npix = (frame == null) ? header.width * header.height : frame.iw * frame.ih;
        int available, clear, codeMask, codeSize, endOfInformation, inCode, oldCode, bits, code, count,
                i, datum,
                dataSize, first, top, bi, pi;

        if (mainPixels == null || mainPixels.length < npix) {
            // Allocate new pixel array.
            mainPixels = bitmapProvider.obtainByteArray(npix);
        }
        if (prefix == null) {
            prefix = new short[MAX_STACK_SIZE];
        }
        if (suffix == null) {
            suffix = new byte[MAX_STACK_SIZE];
        }
        if (pixelStack == null) {
            pixelStack = new byte[MAX_STACK_SIZE + 1];
        }

        // Initialize GIF data stream decoder.
        dataSize = readByte();
        clear = 1 << dataSize;
        endOfInformation = clear + 1;
        available = clear + 2;
        oldCode = NULL_CODE;
        codeSize = dataSize + 1;
        codeMask = (1 << codeSize) - 1;
        for (code = 0; code < clear; code++) {
            // XXX ArrayIndexOutOfBoundsException.
            prefix[code] = 0;
            suffix[code] = (byte) code;
        }

        // Decode GIF pixel stream.
        datum = bits = count = first = top = pi = bi = 0;
        for (i = 0; i < npix; ) {
            // Load bytes until there are enough bits for a code.
            if (count == 0) {
                // Read a new data block.
                count = readBlock();
                if (count <= 0) {
                    status = STATUS_PARTIAL_DECODE;
                    break;
                }
                bi = 0;
            }

            datum += (((int) block[bi]) & 0xff) << bits;
            bits += 8;
            bi++;
            count--;

            while (bits >= codeSize) {
                // Get the next code.
                code = datum & codeMask;
                datum >>= codeSize;
                bits -= codeSize;

                // Interpret the code.
                if (code == clear) {
                    // Reset decoder.
                    codeSize = dataSize + 1;
                    codeMask = (1 << codeSize) - 1;
                    available = clear + 2;
                    oldCode = NULL_CODE;
                    continue;
                }

                if (code > available) {
                    status = STATUS_PARTIAL_DECODE;
                    break;
                }

                if (code == endOfInformation) {
                    break;
                }

                if (oldCode == NULL_CODE) {
                    pixelStack[top++] = suffix[code];
                    oldCode = code;
                    first = code;
                    continue;
                }
                inCode = code;
                if (code >= available) {
                    pixelStack[top++] = (byte) first;
                    code = oldCode;
                }
                while (code >= clear) {
                    pixelStack[top++] = suffix[code];
                    code = prefix[code];
                }
                first = ((int) suffix[code]) & 0xff;
                pixelStack[top++] = (byte) first;

                // Add a new string to the string table.
                if (available < MAX_STACK_SIZE) {
                    prefix[available] = (short) oldCode;
                    suffix[available] = (byte) first;
                    available++;
                    if (((available & codeMask) == 0) && (available < MAX_STACK_SIZE)) {
                        codeSize++;
                        codeMask += available;
                    }
                }
                oldCode = inCode;

                while (top > 0) {
                    // Pop a pixel off the pixel stack.
                    mainPixels[pi++] = pixelStack[--top];
                    i++;
                }
            }
        }

        // Clear missing pixels.
        for (i = pi; i < npix; i++) {
            mainPixels[i] = 0;
        }
    }
175014
public static byte[] getPixelsBGR(BufferedImage img, int y, int w, byte[] array, int[] temp) {
    final int x = 0;
    final int h = 1;

    assert array.length == temp.length * nrChannels(img);
    assert (temp.length == w);

    int imageType = img.getType();
    Raster raster;
    switch (imageType) {
      case BufferedImage.TYPE_3BYTE_BGR:
      case BufferedImage.TYPE_4BYTE_ABGR:
      case BufferedImage.TYPE_4BYTE_ABGR_PRE:
      case BufferedImage.TYPE_BYTE_GRAY:
        raster = img.getRaster();
        //int ttype= raster.getTransferType();
        raster.getDataElements(x, y, w, h, array);
        break;
      case BufferedImage.TYPE_INT_BGR:
        raster = img.getRaster();
        raster.getDataElements(x, y, w, h, temp);
        ints2bytes(temp, array, 0, 1, 2);  // bgr -->  bgr
        break;
      case BufferedImage.TYPE_INT_RGB:
        raster = img.getRaster();
        raster.getDataElements(x, y, w, h, temp);
        ints2bytes(temp, array, 2, 1, 0);  // rgb -->  bgr
        break;
      case BufferedImage.TYPE_INT_ARGB:
      case BufferedImage.TYPE_INT_ARGB_PRE:
        raster = img.getRaster();
        raster.getDataElements(x, y, w, h, temp);
        ints2bytes(temp, array, 2, 1, 0, 3);  // argb -->  abgr
        break;
      case BufferedImage.TYPE_CUSTOM: // TODO: works for my icon image loader, but else ???
        img.getRGB(x, y, w, h, temp, 0, w);
        ints2bytes(temp, array, 2, 1, 0, 3);  // argb -->  abgr
        break;
      default:
        img.getRGB(x, y, w, h, temp, 0, w);
        ints2bytes(temp, array, 2, 1, 0);  // rgb -->  bgr
        break;
    }

    return array;
  }
1331921
def _produce_jbig2_images(jbig2_groups, root, log, options):
    """"""

    def jbig2_group_futures(executor, root, groups):
        for group, xref_exts in groups.items():
            prefix = f'group{group:08d}'
            future = executor.submit(
                jbig2enc.convert_group,
                cwd=fspath(root),
                infiles=(img_name(root, xref, ext) for xref, ext in xref_exts),
                out_prefix=prefix,
            )
            yield future

    def jbig2_single_futures(executor, root, groups):
        for group, xref_exts in groups.items():
            prefix = f'group{group:08d}'
            # Second loop is to ensure multiple images per page are unpacked
            for n, xref_ext in enumerate(xref_exts):
                xref, ext = xref_ext
                future = executor.submit(
                    jbig2enc.convert_single,
                    cwd=fspath(root),
                    infile=img_name(root, xref, ext),
                    outfile=root / f'{prefix}.{n:04d}',
                )
                yield future

    if options.jbig2_page_group_size > 1:
        jbig2_futures = jbig2_group_futures
    else:
        jbig2_futures = jbig2_single_futures

    with concurrent.futures.ThreadPoolExecutor(max_workers=options.jobs) as executor:
        futures = jbig2_futures(executor, root, jbig2_groups)
        for future in concurrent.futures.as_completed(futures):
            proc = future.result()
            log.debug(proc.stderr.decode())
652725
def asrgb(self, uint8=False, alpha=None, colormap=None,
              dmin=None, dmax=None, **kwargs):
        
        data = self.asarray(**kwargs)
        self = self.keyframe  # self or keyframe
        photometric = self.photometric
        PHOTOMETRIC = TIFF.PHOTOMETRIC

        if photometric == PHOTOMETRIC.PALETTE:
            colormap = self.colormap
            if (colormap.shape[1] < 2**self.bitspersample or
                    self.dtype.char not in 'BH'):
                raise ValueError('cannot apply colormap')
            if uint8:
                if colormap.max() > 255:
                    colormap >>= 8
                colormap = colormap.astype('uint8')
            if 'S' in self.axes:
                data = data[..., 0] if self.planarconfig == 1 else data[0]
            data = apply_colormap(data, colormap)

        elif photometric == PHOTOMETRIC.RGB:
            if 'ExtraSamples' in self.tags:
                if alpha is None:
                    alpha = TIFF.EXTRASAMPLE
                extrasamples = self.extrasamples
                if self.tags['ExtraSamples'].count == 1:
                    extrasamples = (extrasamples,)
                for i, exs in enumerate(extrasamples):
                    if exs in alpha:
                        if self.planarconfig == 1:
                            data = data[..., [0, 1, 2, 3+i]]
                        else:
                            data = data[:, [0, 1, 2, 3+i]]
                        break
            else:
                if self.planarconfig == 1:
                    data = data[..., :3]
                else:
                    data = data[:, :3]
            # TODO: convert to uint8?

        elif photometric == PHOTOMETRIC.MINISBLACK:
            raise NotImplementedError()
        elif photometric == PHOTOMETRIC.MINISWHITE:
            raise NotImplementedError()
        elif photometric == PHOTOMETRIC.SEPARATED:
            raise NotImplementedError()
        else:
            raise NotImplementedError()
        return data
593300
def extract_guts(image_path,
                 tar,
                 file_filter=None,
                 tag_root=True,
                 include_sizes=True):

    '''
    '''
    if file_filter is None:
        file_filter = get_level('IDENTICAL')

    results = dict()
    digest = dict()
    allfiles = []

    if tag_root:
        roots = dict()

    if include_sizes: 
        sizes = dict()

    for member in tar:
        member_name = member.name.replace('.','',1)
        allfiles.append(member_name)
        included = False
        if member.isdir() or member.issym():
            continue
        elif assess_content(member,file_filter):
            digest[member_name] = extract_content(image_path, member.name, return_hash=True)
            included = True
        elif include_file(member,file_filter):
            hasher = hashlib.md5()
            buf = member.tobuf()
            hasher.update(buf)
            digest[member_name] = hasher.hexdigest()
            included = True
        if included:
            if include_sizes:
                sizes[member_name] = member.size
            if tag_root:
                roots[member_name] = is_root_owned(member)

    results['all'] = allfiles
    results['hashes'] = digest
    if include_sizes:
        results['sizes'] = sizes
    if tag_root:
        results['root_owned'] = roots
    return results
1231927
def get_image(dataset):
    """"""
    dim, nrow, ncol = dataset.shape
    uint8_dataset = dataset.astype('uint8')
    if not (uint8_dataset == dataset).all():
        message = (
            "\nYour image was cast to a `uint8` (`<img>.astype(uint8)`), "
            "but some information was lost.\nPlease check your gif and "
            "convert to uint8 beforehand if the gif looks wrong."
        )
        warnings.warn(message)
    image = [[
            struct.pack(
                'BBB',
                uint8_dataset[0, i, j],
                uint8_dataset[1, i, j],
                uint8_dataset[2, i, j]
            )
            for j in range(ncol)]
        for i in range(nrow)]
    return image
546929
def grab(self, monitor):
        # type: (Monitor) -> ScreenShot
        

        # Convert PIL bbox style
        if isinstance(monitor, tuple):
            monitor = {
                "left": monitor[0],
                "top": monitor[1],
                "width": monitor[2] - monitor[0],
                "height": monitor[3] - monitor[1],
            }

        ximage = self.xlib.XGetImage(
            MSS.display,
            self.drawable,
            monitor["left"],
            monitor["top"],
            monitor["width"],
            monitor["height"],
            PLAINMASK,
            ZPIXMAP,
        )

        try:
            bits_per_pixel = ximage.contents.bits_per_pixel
            if bits_per_pixel != 32:
                raise ScreenShotError(
                    "[XImage] bits per pixel value not (yet?) implemented: {}.".format(
                        bits_per_pixel
                    )
                )

            raw_data = ctypes.cast(
                ximage.contents.data,
                ctypes.POINTER(
                    ctypes.c_ubyte * monitor["height"] * monitor["width"] * 4
                ),
            )
            data = bytearray(raw_data.contents)
        finally:
            # Free
            self.xlib.XDestroyImage(ximage)

        return self.cls_image(data, monitor)
785699
def tenengrad(img, ksize=3):
    '''''''
    Gx = cv2.Sobel(img, ddepth=cv2.CV_64F, dx=1, dy=0, ksize=ksize)
    Gy = cv2.Sobel(img, ddepth=cv2.CV_64F, dx=0, dy=1, ksize=ksize)
    FM = Gx*Gx + Gy*Gy
    mn = cv2.mean(FM)[0]
    if np.isnan(mn):
        return np.nanmean(FM)
    return mn