# Porosity Analyzer for Metallography (AM & Coatings) (`jovianlabs/porosity-analyzer`) Actor

Area porosity from polished cross-section micrographs (optical or SEM): porosity % with 95 % confidence interval and relative accuracy, pore sizes, largest pores, round vs lack-of-fusion pores, quality checks and a PDF report.

- **URL**: https://apify.com/jovianlabs/porosity-analyzer.md
- **Developed by:** [Jovian Labs](https://apify.com/jovianlabs) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1,000.00 / 1,000 images

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Porosity Analyzer for Metallography (AM & Coatings)

Measure the porosity of polished cross-sections in seconds: upload micrographs of metal additive manufacturing parts, castings, sintered parts or thermal spray coatings, and get the area porosity with its confidence interval, the pore size distribution, the largest pores, the share of round versus lack-of-fusion pores and a PDF report you can file with the build or batch record.

**Try it in one click:** leave the image list empty and press Start. The Actor generates five synthetic cross-sections with a known porosity (one of them with mounting resin on the edge), analyses them and shows how close the measurement is to the truth. Demo runs are free.

### What you get

| Output | Content |
|---|---|
| Dataset item | porosity % with its 95 % confidence interval, relative accuracy (%RA), overall porosity, material area, pore count and density, pore D50/D90, largest pore, share of round and irregular pores, threshold sensitivity, quality status and checks |
| `REPORT.pdf` | main results, pore sizes, pore types, the five largest pores with their position, detection check image, porosity per field, method, quality checks, traceability |
| `pores.csv` | one row per pore: type, cut by border, area, equivalent diameter, min/max Feret, roundness, circularity, aspect ratio, position in µm |
| `control-sheet.jpg` | every field with the detected pores outlined by type, to check the detection at a glance |
| `summary.json` | all statistics in machine-readable form |

### Who it is for

- Metal additive manufacturing (laser or electron beam powder bed fusion, DED): process window development, build qualification, lot release
- Thermal spray and coating shops measuring coating porosity on cross-sections
- Foundries, powder metallurgy and ceramics labs
- Quality engineers who count pores by hand in ImageJ or rate them against comparison charts
- AI agents that need porosity numbers from micrographs (callable through the Apify MCP server)

### How it works

1. The pixel size comes from the microscope metadata (Zeiss or Thermo Fisher SEM TIFF), the scale bar of the image data band, or the value you give (typical for optical micrographs).
2. Uneven illumination is corrected (darker corners are common on optical microscopes), then the image is smoothed lightly.
3. The pore threshold is the lower of the Otsu threshold and the noise limit of the material, so that grain contrast and polishing scratches are not counted as pores when porosity is low. The run reports how much the porosity changes if the threshold moves slightly: a direct measure of how clear-cut the result is.
4. Large dark regions touching the field border (mounting resin, empty space) are excluded from the material instead of being counted as pores.
5. Each field gives a porosity (pore area / material area). The Actor reports the mean, the 95 % confidence interval (Student t × SD / √n) and the relative accuracy %RA, as in quantitative metallography, and how many fields would bring %RA down to 10 %. With fewer than 3 images, each image is split into 16 sub-fields and the report says so.
6. Every pore is measured (area, equivalent diameter, Feret diameters, roundness) and typed from its shape: round (gas or keyhole), irregular (likely lack of fusion) or intermediate. The roundness thresholds are adjustable, because they depend on the alloy and process.
7. Eight automatic checks rate the run green, amber or red: scale consistency, number of fields, relative accuracy, threshold sensitivity, pore/material contrast, pores too small to classify, saturation and share of the field outside the material.

The approach is close to the automatic image analysis method (Method B) of ASTM E2109 for thermal sprayed coatings and to the field statistics of quantitative metallography.

### Accuracy

Measured on synthetic cross-sections whose porosity is known to the pixel (texture, polishing scratches, noise and blur included):

| True porosity | Measured | Pores counted | Largest pore |
|---|---|---|---|
| 0.59 % | 0.59 % | 29 of 29 | 137.0 µm (true 138.6) |
| 2.17 % | 2.19 % | 104 of 104 | 152.7 µm (true 152.8) |
| 6.16 % | 6.21 % | 244 of 244 | 153.7 µm (true 154.0) |

With strong uneven illumination (corners 35 % darker), the illumination correction keeps the result at 2.17 % for a true 2.14 %, where a plain threshold would read 1.83 %. The share of porosity coming from irregular pores was measured within 1 point of the truth.

### Input example

```json
{
  "imageUrls": [
    "https://example.com/build-12-field1.tif",
    "https://example.com/build-12-field2.tif",
    "https://example.com/build-12-field3.tif",
    "https://example.com/build-12-field4.tif",
    "https://example.com/build-12-field5.tif"
  ],
  "pixelSizeUm": "0.5",
  "sampleName": "BUILD-12-XY"
}
```

Set `"reportLanguage": "fr"` for a report in French. Use `scaleBarUm` instead of `pixelSizeUm` when the images have a data band with a scale bar, or nothing at all for original Zeiss or Thermo Fisher SEM TIFF files.

Use 5 or more fields spread over the section, all at the same magnification, as-polished and unetched. Images must be direct download links (TIFF, PNG or JPG, up to 60 MB each).

### Pricing

You pay per image analysed. There is no charge for images that cannot be downloaded, and demo runs (no image URLs) are free.

### Good to know

- Pores must be darker than the material (the usual case in bright-field optical microscopy and in SEM). Tick `poresAreBright` for the opposite.
- Oxides, inclusions or dark phases as dark as pores are counted as pores. Preparation artefacts (pull-outs, smearing, edge rounding) are not detected automatically: check the control sheet.
- A 2D section measures area porosity, not volume porosity, and cuts pores at random heights. Use CT or the Archimedes method for bulk density.
- Pore typing from shape is indicative.
- This is automated image analysis, not an accredited (ISO/IEC 17025) laboratory measurement.
- Need a report reviewed and signed by a materials imaging scientist? A verified analysis service is available on request (contact through the Actor's issues tab).

# Actor input Schema

## `imageUrls` (type: `array`):

Direct links to micrographs of ONE sample (TIFF, PNG or JPG), all at the same magnification. Use 5 or more fields spread over the section. Leave empty to try the Actor on built-in synthetic cross-sections with known porosity (free).

## `scaleBarUm` (type: `string`):

Length printed on the scale bar of the image data band, in micrometres (e.g. 100). The bar is detected automatically. Optional for original TIFF files from Zeiss or Thermo Fisher (FEI) SEMs: the pixel size is then read from the file metadata.

## `pixelSizeUm` (type: `string`):

Use for optical micrographs without a data band, e.g. 0.5 at 200x on many cameras. Overrides everything else.

## `sampleName` (type: `string`):

Shown on the report.

## `poresAreBright` (type: `boolean`):

Leave off for the usual case (dark pores on bright polished metal or ceramic).

## `excludeOutside` (type: `boolean`):

Large dark regions touching the image border (5 % of the field or more) are treated as outside the material, not as pores.

## `roundnessRound` (type: `string`):

Pores with roundness (4·area / π·max Feret²) at or above this value are typed as round (gas or keyhole).

## `roundnessIrregular` (type: `string`):

Pores below this roundness are typed as irregular (likely lack of fusion). Thresholds depend on the alloy and process.

## `threshold` (type: `string`):

Optional, between 0 and 1 on the normalised image. Leave empty for the automatic threshold, which also corrects uneven illumination.

## `reportLanguage` (type: `string`):

Language of the PDF report and CSV headers.

## `maxImages` (type: `integer`):

Each analysed image is billed once.

## Actor input object example

```json
{
  "sampleName": "SAMPLE-01",
  "poresAreBright": false,
  "excludeOutside": true,
  "roundnessRound": "0.70",
  "roundnessIrregular": "0.45",
  "reportLanguage": "en",
  "maxImages": 20
}
```

# Actor output Schema

## `results` (type: `string`):

Porosity with its 95 % confidence interval and relative accuracy, pore sizes, largest pore, pore types and quality status.

## `report` (type: `string`):

Full report: porosity, statistics, pore sizes and types, largest pores, detection check, per-image results, quality checks, method and traceability.

## `controlSheet` (type: `string`):

Every field with the detected pores outlined by type, to check the detection at a glance.

## `pores` (type: `string`):

One row per pore: type, border cut, area, equivalent diameter, min/max Feret, roundness, circularity, position.

## `summary` (type: `string`):

All statistics in machine-readable form.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("jovianlabs/porosity-analyzer").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("jovianlabs/porosity-analyzer").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call jovianlabs/porosity-analyzer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jovianlabs/porosity-analyzer"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/5rkneXXS3ocIhPCJc/builds/GUiPIFRhrmmtCE5lk/openapi.json
