---
title: Separating Touching Particles
url: https://oosioo.com/en/p/%EB%B6%99%EC%9D%80-%EC%9E%85%EC%9E%90-%EB%96%BC%EC%96%B4-%EB%82%B4%EA%B8%B0
date: 2026-10-16T11:32:45+00:00
author: SYSOP
summary: Should touching coffee particles be split or thrown away? Using fake photos with a known answer, I graded discarding, the distance watershed, coffeegrindsize's breakup, Cellpose-SAM and a U-Net trained on fakes. Even discarding exactly the touching blobs threw out 93% of particles over 1.5 mm and shrank the volume median by 15%, and on the real photo the volume median ranged from 710 to 1,057 µm depending on the method.
---
# Separating Touching Particles

Last time I graded this series' measuring algorithm with fake coffee photos whose answer I knew. On fakes made to look like the real thing, the volume median came out 33% too large, and most of that error came from two or three touching particles being caught as one blob. Thirty percent of the particles of 330 µm and above merged with a neighbour that way.

There are two ways to deal with a touching blob. You can split it and measure the pieces, or you can leave it out of the count altogether. This post grades both on the same fake photos. The first question is this: when you throw touching blobs away, what goes out with them?

## Why touching particles are a problem

The international standard for static image analysis of particle size, ISO 13322-1, puts this at the head of the method: "It is a prime requirement of the method that measurements shall be made on isolated particles. Touching particles measured as one particle without a proper separation will introduce error." Its section on sample preparation also asks you to adjust the number of particles in a frame so as to minimize the number of touching particles.

Coffee grounds touch for two reasons. One is that they land next to each other by chance when sprinkled on the paper. That is a measurement problem. The other is that the grounds were stuck together to begin with. Méndez Harper and colleagues (2024) reported that static charge generated during grinding makes particles clump together. Wetting the beans with a tiny amount of water before grinding (under 0.05 mL per gram) shifted the particle-size distribution markedly, partly because fewer clumps formed, and espresso made from those grounds was at least 15% more concentrated. Clumps like these are not an optical illusion in the photo. They are real objects.

This post deals with the first case: particles that happen to touch on the paper. Gagné's coffeegrindsize manual describes this step carefully. After sprinkling, check by eye for grains that sit too close together, and break the clumps up by moving particles with a chopstick or by pressing a finger on them and spraying them back. It is very important to spray all of them back, "otherwise you may be preferentially removing particles of a given size, which will bias your measured distribution."

![Three panels side by side. The left panel is part of a fake coffee photo, with black angular particles gathered in a few clusters. The middle panel is the answer for the same spot, with each particle in its own colour, so individual particles can be told apart even inside a cluster. The right panel shows the blobs measured as is, by grouping touching pixels; in the large blob at the lower left, five or six true particles share a single colour](/uploads/1cfbf64b6ac33f63.webp =760)

When several true particles end up in one colour, as at the lower right of the picture, the measurement records them as a single large particle.

## What goes missing when you discard

The easiest remedy is to leave out any blob that looks like it is made of touching particles. But first we need to know how good this remedy could possibly be. So I gave the job to someone who can do what the photo alone cannot: a referee who knows the answer and discards exactly the blobs that hold two or more particles. It never discards a wrong blob and never misses one. This is the best result discarding can ever give.

The volume median came out 15% smaller than the truth. An error of +33% had swung to the other side. Fifty-one percent of the particles of 330 µm and above were discarded.

![Line chart. The horizontal axis is the true particle diameter in bins from 330–450 µm to 1500–2200 µm; the vertical axis is the share of particles of that size that get discarded. When a referee who knows the answer discards only touching blobs, the share rises steeply with size: 41%, 45%, 56%, 65%, 74% and 93%. When blobs with solidity below 0.85 are discarded, it rises from 30% to 72%. The share scored as merged when measuring as is stays flat at 20–32% regardless of size](/uploads/a78c648a149a1c21.webp =760)

Split by size, the reason is clear. Of particles 330–450 µm across, 41% were discarded; of particles 1.5–2.2 mm across, 93% were. A larger particle has a longer perimeter, so there is more room for other particles to touch it. A large particle carrying just one small neighbour is thrown out together with the whole blob.

The orange line makes this sharper. Measured as is, with nothing discarded, 20–30% of particles are scored as "merged" regardless of size. A large particle with a small neighbour attached still takes up most of the blob, so it is often scored as "matched". Its measured size is just a little too big. Discarding throws out such blobs whole. A large particle that used to cause a small error now disappears.

This has the same shape as a problem already known in image measurement. Particles cut by the edge of the photo cannot be measured in full and are usually dropped. Whiting and colleagues (2019) at the US National Institute of Standards and Technology (NIST) wrote that "since larger particles have a higher probability of being vetoed by the edge-exclusion algorithm, the measured PSD may be significantly skewed." So they computed, for each size, the probability that a particle survives without touching the edge, and corrected the distribution with it. The edge is in a fixed place, so that probability can be computed. Touching depends on how densely the grounds were sprinkled and how they cluster, which makes it much harder to compute.

### Discarding by solidity

A common way to pick out touching blobs from the photo alone is solidity: the blob's area divided by the area of the smallest convex polygon that encloses it. When several particles stick together, the gaps between them cave in and the value drops. In "What Is a Diameter?", I also dropped blobs with solidity below 0.85 when computing shape statistics.

![Two-panel chart. On the left, the horizontal axis is the solidity cut-off (0.70 to 0.95) and the vertical axis is the volume-median error: +21% at 0.70, +15% at 0.75, +6% at 0.80, −3% at 0.85, −5% at 0.90 and −31% at 0.95. The perfect referee's −15% is drawn as a dashed line. On the right, against the same axis, the share of large particles discarded rises from 8% to 100%, while the merged particles that remain fall from 23% to 0%](/uploads/b1e25dd2a09d9d4b.webp =760)

As the cut-off moves, two errors move in opposite directions. A low cut-off leaves touching blobs in, so sizes come out too large. A high cut-off throws away many large particles, so sizes come out too small. The curve passes near the truth at 0.85 (−3%) and 0.90 (−5%).

An error of −3% at 0.85 does not mean discarding by solidity is accurate. At this cut-off, 38% of the large particles are still discarded and 6% remain merged. The "too small" from discarding and the "too large" from the remaining blobs happen to be about the same size and cancel. The discarded share also depends on size: 30% of the 330–450 µm particles and 72% of the 1.5–2.2 mm particles were thrown out.

A number that comes out right by cancellation wobbles when conditions change. On fakes built by pasting real particles cut out of Gagné's photo (described below), the same 0.85 cut-off measured the volume median 12% too large.

## Splitting ① Distance watershed

The oldest way to split rather than discard is the watershed. Beucher and Lantuéjoul first used it in 1979 to find contours in pictures of gas bubbles. Measure, for each pixel inside a blob, the distance to the nearest edge, and the middle of each particle becomes a peak. Put a seed on each peak, grow regions outward as if filling with water, and draw a boundary along the valley where two regions meet.

The method's long-standing weakness is over-segmentation. If every little bump counts as a peak, one particle is cut into several pieces. So a peak has to rise by at least some height h before it becomes a seed. Episode 8 used h = 1.5 pixels.

![Three panels. On the left, the distance to the edge for blobs in part of a fake photo is shown as brightness, so the middle of each particle glows; the large blob at the lower left glows as a single elongated shape. In the middle, the same spot split by watershed: several blobs are cut into two pieces, but the large blob at the lower left keeps a single colour. On the right, a chart with the minimum peak height h (0.25 to 4 pixels) on the horizontal axis: merged rises from 17% to 29%, the volume-median error from 10% to 27%, and fragments of over-split particles fall from 1.5% to 0%](/uploads/a0ea47be98409091.webp =760)

The lower the h, the better the result. At h = 0.25 pixels, merging fell from 30% to 17% and the volume-median error from 33% to 10%. The over-splitting I had worried about barely appeared. Even at the lowest h, fragments numbered only 1.5% of the large particles.

But no matter how low h went, merging never fell below 17%. The blob at the lower left of the middle panel is an example. When angular shards overlap, the distance map has only one peak. With no narrow waist between them, there is no valley to cut along. The distance watershed is a method for round particles that only just touch.

## Splitting ② coffeegrindsize's breakup

coffeegrindsize has a feature that breaks up blobs using brightness. The manual describes it as trying to "reject the clumps that contain more than one coffee particle, which were too close together in the picture," by analysing "the increase of brightness near the edges of the coffee particles." I read the code, ported it, and graded it on the same fakes. It works like this:

1. Among the pixels darker than the threshold, take the darkest as a seed, and treat the pixels connected to it as one group
2. From each pixel in the group, draw a straight line to the nearest "core" pixel that is nearly as dark as the seed
3. If somewhere along that path the brightness rises well above the seed's (a bright valley), the pixel is judged not to belong to this particle and is not accepted

One point matters a great deal. Rejected pixels are not split off into a particle of their own. The code marks every pixel in the group as "already counted", accepted or not (`counted[iclust] = True`). So a neighbour that was stuck to the seed particle cannot be picked up as its own particle on a later pass. It vanishes. This is exactly what the manual means by "reject". It does not split the neighbour off; it deletes it.

![Two panels. On the left is the answer, with each particle in its own colour. On the right, the same spot of the fake photo after coffeegrindsize's breakup: pixels accepted as particles are outlined in orange, and pixels rejected and lost are painted purple. In the blob at the lower right, a whole neighbouring particle that was stuck to a large one has turned purple, and thin purple rims also surround many particles](/uploads/6eeac872bca8b9cf.webp =760)

Averaged over three real-like fakes: 24% of the large particles were still merged, 4% vanished, and the volume median came out 25% too large. That is only a little better than doing nothing (33%). Overlapping shards have no bright valley between them, so no breakup happens.

There was an unexpected benefit, too. The size bias of matched particles fell from +6% to +0.7%. Half-bright pixels at blurred edges register as "bright valleys" and get trimmed off. The feature partly fixes the threshold bias seen in episode 8. In exchange you get an odd combination: the number median is off by only 1%, while the volume median is off by 25%.

The manual warns that the feature is slow. My port took about 30 seconds on one 2400 × 1800 photo. Its key value, 0.35, is the one we saw in episode 8: changed from 0.07 to 0.2 and then to 0.35 while looking at photos from two grinders by eye.

## Splitting ③ Learned models

Instead of writing rules by hand, you can train a model on photos that come with answers. I tried two.

**Cellpose-SAM.** A generalist model built to segment microscope images of cells. Stringer and colleagues' Cellpose (2021) predicts, for every pixel, the direction of a "flow" toward the cell's centre, follows those flows, and groups pixels that end up in the same place into one cell. It is good at separating cells that touch. Pachitariu and colleagues (2025) attached the image encoder from Meta's Segment Anything (SAM) and retrained it on 22,826 images with 3.34 million outlines. This model had never seen coffee. I used it as is: I inverted the photo, since coffee is dark on a bright background, and told it only that particles are about 8 pixels across. Without that size hint it missed 69–79% of the large particles.

**A U-Net trained on fakes.** I made training data with the fake-photo generator from episode 8. Instead of the exact values fitted to the one real photo, though, I varied coverage (1–25%), clustering, angularity, blur, noise, uneven lighting and magnification over wide ranges (domain randomization). On 240 such photos of 1024 × 768 pixels, I trained a small U-Net that predicts, for every pixel, whether it belongs to a particle and how close it is to a particle's centre. Places where the centre score is high become seeds, and the watershed does the splitting. Making the data and training took about 30 minutes on a laptop RTX 3070. The test photos were made with seeds not used in training.

## Grading on different test sheets

Here episode 8's warning comes back. If the fake is built on the same assumptions as the algorithm, the score is inflated (the inverse crime). A U-Net trained on fakes comes from the same family as the generator that made the fakes, so it carries exactly that risk.

So I made three kinds of test sheet:

- **Real-like fakes**: episode 8's generator as is, fitted to the blur, noise and coverage (6.1%) of Gagné's photo
- **Dense fakes**: the same generator, covering 15% of the paper
- **Cut-and-paste fakes**: a new test sheet with no link to the generator. I cut 699 blobs out of Gagné's photo, each at least 4 pixels from any neighbour, blurred rims included, and sprinkled them in clusters onto blank paper. No angular polygons, no Gaussian blur. The answer is the area of each cut-out particle

The cut-and-paste fakes have limits too. Only particles that sat apart from their neighbours were cut out, so, as we saw above, large particles were picked less often. No cut-out particle is wider than 1.34 mm.

![Two-panel horizontal bar chart. Six methods (as is, discarding solidity below 0.85, distance watershed, coffeegrindsize breakup, Cellpose-SAM, U-Net trained on fakes) are graded on three test sheets (real-like fakes, cut-and-paste fakes, dense fakes). On the left, the volume-median error: as is +33, +60, +63%; discarding by solidity −3, +12, −1%; distance watershed +12, +22, +19%; coffeegrindsize breakup +25, +30, +47%; Cellpose-SAM −4, +4, −3%; U-Net +2, −5, +2%. On the right, the share of large particles still merged](/uploads/9022266b94d694e6.webp =760)

Detailed numbers, averaged over three real-like fakes:

| | Matched | Merged | Discarded or missed | Volume-median error | Number-median error |
|---|---|---|---|---|---|
| As is | 70% | 30% | 0% | +33% | +8% |
| Referee who knows the answer discards | 49% | 0% | 51% | −15% | −5% |
| Discard solidity below 0.85 | 56% | 6% | 38% | −3% | −1% |
| Distance watershed (h 0.5) | 82% | 18% | 0% | +12% | +8% |
| coffeegrindsize breakup | 72% | 24% | 4% | +25% | +1% |
| Cellpose-SAM | 68% | 8% | 25% | −4% | +6% |
| U-Net trained on fakes | 88% | 11% | 1% | +2% | +1% |

The U-Net kept the volume median within 5% on all three sheets, including −5% on the cut-and-paste fakes that have no link to its generator. On that sheet, though, it produced fragments amounting to 8% of the large particles. The rims and inner brightness of real particles differed from the fakes it learned from, and the model cut some of them in two.

Cellpose-SAM's numbers need careful reading. Its volume-median error is small, −4%, but it failed to find 25% of the large particles at all. By size, it missed 70% of the particles between 1.5 and 2.2 mm. The error is small because the side that measures too large (8% merged) and the side that measures too small (large particles missed) cancel each other. On the dense fakes it missed 37% and still had a volume error of −3%. Like discarding by solidity, it looks good as a single number and is a cancellation underneath. On the cut-and-paste fakes, missing fell to 4%. A model trained on cell images seems more at home with the rims of real photos than with a smooth Gaussian blur.

## On the real photo

Finally, I ran the six methods on the whole of Gagné's example photo. The real photo has no answer key, so it cannot be graded. What we can see is how far the methods disagree.

![On the left, the same part of the real photo split by the six methods, in two rows. "As is" groups touching blobs in one colour, and discarding by solidity leaves touching blobs unpainted. The distance watershed and coffeegrindsize breakup split some of them, Cellpose-SAM draws rounded outlines and wraps a few faint particles generously, and the U-Net splits blobs most finely. On the right, a bar chart of the volume and number medians over the whole of Gagné's photo: as is 1,057 and 606 µm, discarding by solidity 878 and 572 µm, distance watershed 913 and 594 µm, coffeegrindsize breakup 963 and 574 µm, Cellpose-SAM 933 and 695 µm, U-Net 710 and 513 µm](/uploads/e492d0eca3f1b8e3.webp =760)

On the same photo, the volume median ranged from 710 µm to 1,057 µm: a factor of 1.5. The U-Net, the most accurate method on the fakes, gave the smallest value and counted the most blobs, 2,793. Of the blobs measured as is that have solidity of 0.9 or more and so look like single particles, the U-Net split about 10% into two or more. For the distance watershed that share was 0.3%; for Cellpose-SAM, 0%.

Whether the U-Net over-split the real particles or found boundaries the other methods missed cannot be told from this photo alone. Since it produced fragments on the cut-and-paste fakes, the former is possible. coffeegrindsize's breakup threw away 14% of the below-threshold pixels on the real photo, compared with 13% on the real-like fakes and 24% on the cut-and-paste fakes.

The spread between methods (a factor of 1.5) is far bigger than the errors each method showed on the fakes. That means the fake test sheets do not yet resemble the real thing closely enough. To settle the answer for the real photo, we will eventually have to check against physical particles of known size.

## Try it yourself

In the simulation below you can switch methods and watch the same photo split differently. The picture on the left paints each piece in its own colour, with discarded or deleted parts in purple. Press "Score outlines" to colour the outlines of true particles of 330 µm and above as matched (green), merged (orange), discarded (purple) or missed (red).

Under "Discard by solidity", move the cut-off slider and the chart below shows how the discarded share grows with size. Compare it with "Referee discards". Switch to "Real photo" to see the same methods run on part of Gagné's example photo, with medians for the whole photo.

```map /embed/coffee-clumps-2026-en.html 16:12
A simulation comparing ways to separate touching particles. On the left is part of a fake coffee photo (or Gagné's example photo), with the blobs each method produces painted one colour per piece and discarded parts in purple. For the fake photo there is also a score view that colours true particle outlines as matched, merged, discarded or missed. On the right, choose as is, discard by solidity (cut-off 0.70 to 0.95), referee discards, distance watershed (peak height 0.25 to 4 pixels), coffeegrindsize breakup, Cellpose-SAM, or the U-Net trained on fakes, to see the mean score over three real-like fakes and a chart of the merged and discarded shares by size. For the real photo it shows the blob count and the number and volume medians.
```

## What this experiment leaves out

- **Clumps that were stuck together from the start are not covered.** Clumps formed by static charge are real objects, not an illusion in the photo. If such a clump behaves like one particle during extraction, not splitting it may be the right call. Which is right depends on what you want to know
- **There are no fines stuck to large particles.** Fines smaller than 100 µm were not drawn in the fakes. In reality, fines cling to coarse particles, making them a little larger while dropping out of the count themselves
- **The cut-and-paste fakes also come from one real photo.** Only particles that sat apart were cut out, so large particles are scarce, and the answer outlines were set by a threshold of 0.5 on the flattened brightness
- **Cellpose-SAM was used as is, told only one size.** Retraining it on coffee photos could change the result. Other models, such as StarDist, which draws particles as star-shaped polygons, were not tested
- **The U-Net was trained only once.** I did not check how much the results move with different training data and seeds
- **The answer for the real photo is still unknown.** Which of the answers, 1.5 times apart, is right has to be checked with physical particles of known size

## Summary

- Measured as is on real-like fakes, 30% of the particles of 330 µm and above merge with a neighbour, and the volume median comes out 33% too large
- Discarding touching blobs removes the large particles first. Even when a referee who knows the answer discards only the touching blobs, 41% of 330–450 µm particles and 93% of 1.5–2.2 mm particles are thrown out, and the volume median comes out 15% too small. A large particle carrying a single small neighbour is discarded whole
- Discarding blobs with solidity below 0.85 brings the volume-median error to −3%, but only because the discarded share and the remaining merged blobs happen to cancel. On cut-and-paste fakes the same cut-off gave +12%
- The distance watershed leaves 17% merged even with h as low as 0.25 pixels. Overlapping angular shards have no valley to cut along
- coffeegrindsize's breakup does not split a stuck neighbour off; it deletes it. Merging fell from 30% to 24%, and the volume median came out 25% too large
- The U-Net trained on fakes kept the volume median within 5% on all three test sheets. Cellpose-SAM had a small error too, but got it by missing many large particles
- On the real photo, the volume median ranged from 710 to 1,057 µm depending on the method, a factor of 1.5. The method that was most accurate on the fakes gave the smallest answer

Discarding touching blobs is not a neutral choice. Unless you check what is discarded at each size, a distribution that looks clean may be one that has lost its large particles.

## References

- ISO 13322-1:2014. *Particle size analysis — Image analysis methods — Part 1: Static image analysis methods* — 4.2 d) adjust the number of particles per frame to minimize touching particles; 5.2 measurement of isolated particles is a prime requirement. [Official sample](https://cdn.standards.iteh.ai/samples/51257/e5956ce29c644e71ad37738bd690a3cf/ISO-13322-1-2014.pdf)
- Méndez Harper J, et al. (2024). Moisture-controlled triboelectrification during coffee grinding. *Matter* 7(1), 266–283. [doi:10.1016/j.matt.2023.11.005](https://doi.org/10.1016/j.matt.2023.11.005) ([arXiv:2312.03103](https://arxiv.org/abs/2312.03103)) — particle clumping caused by static charge; under 0.05 mL/g of water shifts the size distribution and raises espresso concentration by at least 15%
- Gagné J. *coffeegrindsize*. GitHub. [Link](https://github.com/jgagneastro/coffeegrindsize) — the manual's advice on breaking up clumps and its warning that removing particles of a given size biases the distribution; the breakup in `coffeegrindsize.py` (`def_reference_threshold = 0.4`, `def_maxcost = 0.35`, `nsmooth = 3`, and `counted[iclust] = True`, which marks rejected pixels as counted)
- Whiting JG, Tondare VN, Scott JHJ, Phan TQ, Donmez MA (2019). Uncertainty of particle size measurements using dynamic image analysis. *CIRP Annals* 68(1), 531–534. [doi:10.1016/j.cirp.2019.04.075](https://doi.org/10.1016/j.cirp.2019.04.075) — larger particles are more likely to be excluded at frame edges, skewing the distribution; corrected with a per-size survival probability
- Beucher S, Lantuéjoul C (1979). Use of watersheds in contour detection. *International Workshop on Image Processing: Real-time Edge and Motion Detection/Estimation*, Rennes. — first application of the watershed (gas bubbles)
- Meyer F (2012). The watershed concept and its use in segmentation: a brief history. [arXiv:1202.0216](https://arxiv.org/abs/1202.0216) — the history of over-segmentation and marker-driven watersheds
- Vincent L, Soille P (1991). Watersheds in digital spaces: an efficient algorithm based on immersion simulations. *IEEE Transactions on Pattern Analysis and Machine Intelligence* 13(6), 583–598. [doi:10.1109/34.87344](https://doi.org/10.1109/34.87344)
- Stringer C, Wang T, Michaelos M, Pachitariu M (2021). Cellpose: a generalist algorithm for cellular segmentation. *Nature Methods* 18, 100–106. [doi:10.1038/s41592-020-01018-x](https://doi.org/10.1038/s41592-020-01018-x)
- Pachitariu M, Rariden M, Stringer C (2025). Cellpose-SAM: superhuman generalization for cellular segmentation. *bioRxiv*. [doi:10.1101/2025.04.28.651001](https://doi.org/10.1101/2025.04.28.651001) — SAM image encoder; 22,826 training images and 3,341,254 outlines
- Schmidt U, Weigert M, Broaddus C, Myers G (2018). Cell Detection with Star-Convex Polygons. *MICCAI 2018*, 265–273. [doi:10.1007/978-3-030-00934-2_30](https://doi.org/10.1007/978-3-030-00934-2_30)
- Frei M, Kruis FE (2020). Image-based size analysis of agglomerated and partially sintered particles via convolutional neural networks. *Powder Technology* 360, 324–336. [doi:10.1016/j.powtec.2019.10.020](https://doi.org/10.1016/j.powtec.2019.10.020) — the watershed tends to over-segment because it is sensitive to noise; trained on synthetic images only
- Rühle B, Krumrey JF, Hodoroaba V-D (2021). Workflow towards automated segmentation of agglomerated, non-spherical particles from electron microscopy images using artificial neural networks. *Scientific Reports* 11, 4942. [doi:10.1038/s41598-021-84287-6](https://doi.org/10.1038/s41598-021-84287-6)
- Ronneberger O, Fischer P, Brox T (2015). U-Net: Convolutional Networks for Biomedical Image Segmentation. *MICCAI 2015*. [arXiv:1505.04597](https://arxiv.org/abs/1505.04597)
- Tobin J, et al. (2017). Domain randomization for transferring deep neural networks from simulation to the real world. *IROS 2017*. [arXiv:1703.06907](https://arxiv.org/abs/1703.06907)

## Image credits

- All figures and the simulation: made by me. The real photo and the particles in the cut-and-paste fakes come from Jonathan Gagné's [coffeegrindsize](https://github.com/jgagneastro/coffeegrindsize) example photo ([MIT licence](https://github.com/jgagneastro/coffeegrindsize/blob/master/LICENSE)). The Cellpose-SAM results were obtained with the public model weights as released

