Skip to main content

cp_measure implements CellProfiler measurements in an accessible interface.

Project description

cp_measure: Morphological features for imaging data

Do you need to use CellProfiler features, but you want to do it in a programmatic way? Look no more, this package was developed by and for the click-a-phobic scientists.

Quick overview

Installation

pip install cp-measure

Development

If you want to install it for development use uv.

git clone git@github.com:afermg/cp_measure.git
cd cp_measure
uv sync --all-extras

Usage

Users usually want to calculate all the features. There are four type of measurements, based on their inputs:

  • Type 1: 1 image + 1 set of masks (e.g., intensity)
  • Type 2: 2 images + 1 set of masks (e.g., colocalization)
  • Type 3: 2 sets of masks (e.g., number of neighbors)
  • Type 4: 1 image + 2 sets of masks (e.g., skeleton)

This shows the simplest way to use the first set (1 image, 1 mask set), which currently follows the style of scikit-image (1 image, 1 matrix with non-overlapping labels). IMPORTANT: If you need to match CellProfiler measurements 1:1, you must convert your image arrays to float values between 0 and 1. For instance, if you have an array of data type uint16, you must divide them all by 65535. This is important for radial distribution measurements.

NOTE: The input labels must be sequential (e.g., [1,2,3], not [1,3,4]). You can use skimage.segmentation.relabel_sequential to ensure compliance.

import numpy as np

from cp_measure.bulk import get_core_measurements

measurements = get_core_measurements()
print(measurements.keys())
# dict_keys(['radial_distribution', 'radial_zernikes', 'intensity', 'sizeshape', 'zernike', 'ferret', 'texture', 'granularity'])

import numpy as np
import pandas as pd
from cp_measure.bulk import get_core_measurements

# Create synthetic data
size = 240
rng = np.random.default_rng(42)
pixels = rng.integers(low=1, high=255, size=(size, size))

# Create two similar-sized objects
masks = np.zeros_like(pixels)
masks[50:100, 50:100] = 1  # First square 50x50
masks[80:120, 90:120] = 1  # Major asymmetries on bottom right edge
masks[150:200, 150:200] = 2  # Second square 50x50
masks[175:180, 180:210] = 2  # Minor asymmetries on bottom right edge

# Get measurements
measurements = get_core_measurements()

results = {}
for name, v in measurements.items():
    results = {**results, **v(masks, pixels)}

"""
{'RadialDistribution_FracAtD_1of4': array([0.03673493, 0.05640786]),
 'RadialDistribution_MeanFrac_1of4': array([1.02857809, 1.15072037]),
 'RadialDistribution_RadialCV_1of4': array([0.05539421, 0.04635982]),
 ...
 'Granularity_16': array([97.65759629, 97.64371833])}
"""

Call specific measurements

If you need a specific measurement/feature you can just import it. Note that measurements come in sets, so you have to fetch the one that you specifically require from the resultant dictionary. Any available measurement can be found using code as follows:

import numpy as np

from cp_measure.minimal.measureobjectsizeshape import get_sizeshape

mask = np.zeros((50, 50))
mask[5:-6, 5:-6] = 1
get_sizeshape(mask, None) # pixels, the second argument, is not necessary for this particular measurement

The other available functions are as follows:

measureobjectintensitydistribution.get_radial_zernikes
measureobjectintensity.get_intensity
measureobjectsizeshape.get_zernike
measureobjectsizeshape.get_ferret
measuregranularity.get_granularity
measuretexture.get_texture

And for Type 2 functions:

measurecolocalization.get_correlation_pearson
measurecolocalization.get_correlation_manders_fold
measurecolocalization.get_correlation_rwc
measurecolocalization.get_correlation_costes
measurecolocalization.get_correlation_overlap

For Type 3 functions:

measureobjectoverlap.measureobjectoverlap
measureobjectneghbors.measureobjectneighboors

Work in Progress

You can follow progress here.

Done

  • Type 1 and 2 in sklearn style (multiple integer labels in one mask array)

Pending

  • Add a wrapper for type 3 measurements
  • Type 4 measurements (ObjectSkeleton). We don't know if it is worth implementing.

Additional notes

  • The Image-wide functions will not be implemented directly, they were originally implemented independently to the Object (mask) functions. We will adjust the existing functions assume that an image-wide measurement is the same as measuring an object with the same size as the intensity image.
  • This is not optimised for efficiency (yet). We aim to reproduce the 'vanilla' results of CellProfiler with minimal code changes. Optimisations will be implemented once we come up with a standard interface for functionally-focused CellProfiler components.
  • The functions exposed perform minimal checks. They will fail if provided with empty masks. Not all functions will fail if provided with masks only.

Similar projects

  • spacr: Library to analyse screens, it provides measurements (independent implementation) and a GUI.
  • ScaleFEX: Python pipeline that includes measurements, designed for the cloud.
  • thyme: Rust library to extract a subset of CellProfiler's features efficiently (independent implementation).

Cite

If you used cp_measure in your project, please cite using the following bib entry:

@article{munoz2025cp_measure,
  title={cp\_measure: API-first feature extraction for image-based profiling workflows},
  author={Mu{\~n}oz, Al{\'a}n F and Treis, Tim and Kalinin, Alexandr A and Dasgupta, Shatavisha and Theis, Fabian and Carpenter, Anne E and Singh, Shantanu},
  journal={arXiv preprint arXiv:2507.01163},
  year={2025}
}

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cp_measure-0.1.13.tar.gz (483.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cp_measure-0.1.13-py3-none-any.whl (490.7 kB view details)

Uploaded Python 3

File details

Details for the file cp_measure-0.1.13.tar.gz.

File metadata

  • Download URL: cp_measure-0.1.13.tar.gz
  • Upload date:
  • Size: 483.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.10

File hashes

Hashes for cp_measure-0.1.13.tar.gz
Algorithm Hash digest
SHA256 6858aa5b46f0e9652df70e549867d28880893cf0da52c8deb4bfcd9da1586048
MD5 6515efdc5de8545c37e41d87476bfcf5
BLAKE2b-256 58191ff3bfa695b8b126f817cf4ff08c4f21232389cc95f232f38cef4d8ffbc4

See more details on using hashes here.

File details

Details for the file cp_measure-0.1.13-py3-none-any.whl.

File metadata

File hashes

Hashes for cp_measure-0.1.13-py3-none-any.whl
Algorithm Hash digest
SHA256 3f2a4f8ebe6085834951d3217c45c90b964d81d5bf20eaf9593bc93a4316aa6d
MD5 7b616e093816ec6f882b7d560c2e6819
BLAKE2b-256 4be615abcee160002e9b02fc38d8f0aa63c667283c37f7e52b1d97ab4a0b53c7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page