From cf2004540efb0b9dfde6aafc476dc708180c8fc9 Mon Sep 17 00:00:00 2001 From: Rand McKinney Date: Thu, 20 Mar 2025 15:28:56 -0700 Subject: [PATCH 1/6] Add TrustMark subdirs --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 4a6ecce..98cb697 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,9 @@ /docs/**/readme.md /static/sb-alg-list.json /docs/trustmark/*.md +/docs/trustmark/c2pa/*.md +/docs/trustmark/js/*.md +/docs/trustmark/python*.md # Misc .DS_Store From 774a8b46b0b6ab284de8b8037121faed17020a5b Mon Sep 17 00:00:00 2001 From: Rand McKinney Date: Thu, 20 Mar 2025 15:29:54 -0700 Subject: [PATCH 2/6] Update with TrustMark changes --- docs/trustmark/c2pa/.gitkeep | 0 docs/trustmark/js/.gitkeep | 0 docs/trustmark/python/.gitkeep | 0 docs/trustmark/python/CONFIG.md | 100 ++++++++++++++++++++++++++++++++ scripts/fetch-readme.js | 24 ++++---- sidebars.js | 11 +++- 6 files changed, 120 insertions(+), 15 deletions(-) create mode 100644 docs/trustmark/c2pa/.gitkeep create mode 100644 docs/trustmark/js/.gitkeep create mode 100644 docs/trustmark/python/.gitkeep create mode 100644 docs/trustmark/python/CONFIG.md diff --git a/docs/trustmark/c2pa/.gitkeep b/docs/trustmark/c2pa/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/trustmark/js/.gitkeep b/docs/trustmark/js/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/trustmark/python/.gitkeep b/docs/trustmark/python/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/trustmark/python/CONFIG.md b/docs/trustmark/python/CONFIG.md new file mode 100644 index 0000000..d742b92 --- /dev/null +++ b/docs/trustmark/python/CONFIG.md @@ -0,0 +1,100 @@ +# Configuring TrustMark + +## Overview + +All watermarking algorithms trade off between three properties: + +- **Capacity (bits)** +- **Robustness (to various transformations)** +- **Visibility (of watermark)** + +This document explains how to configure TrustMark to tune these properties, however the default configuration for TrustMark (variant Q, 100% strength, BCH_5 error correction) is sufficient for most use cases. + +## Model variant + +TrustMark has four model variants (**B**, **C**, **P**, and **Q**) that may be selected when instantiating TrustMark. All encode/decode calls on the object will use this variant. + +In general, we recommend using **P** or **Q**: +- **P** is useful for creative applications where very high visual quality is required. +- **Q** is a good all-rounder and is the default. + +> **Note:** Images encoded with one model variant cannot be decoded with another. + +| Variant | Typical PSNR | Model Size Enc/Dec (MB) | Description | +|---------|--------------|-------------------------|-----------------------------------------------------------------------------------------------------| +| **Q** | 43-45 | 17/45 | Default (**Q**uality). Good trade-off between robustness and imperceptibility. Uses ResNet-50 decoder. | +| **B** | 43-45 | 17/45 | (**B**eta). Very similar to Q, included mainly for reproducing the paper. Uses ResNet-50 decoder. | +| **C** | 38-39 | 17/21 | (**C**ompact). Uses a ResNet-18 decoder (smaller model size). Slightly lower visual quality. | +| **P** | 48-50 | 16/45 | (**P**erceptual). Very high visual quality and good robustness. ResNet-50 decoder trained with much higher weight on perceptual loss (see paper). | + +## Watermark strength + +Set the optional `WM_STRENGTH` parameter when encoding (at runtime). +Its default value is `1.0`, and changing it provides a trade-off between **robustness** and **visibility**: + +- Raising its value (for example, to 1.5) improves robustness (so, for example, the watermark survives printing) but increases the likelihood of ripple artifacts. +- Lowering its value (for example, to 0.8) reduces any likelihood of artifacts but compromises on robustness; however it still survives lower noise, screenshotting, or social media. + +For example: + +```python +encoded_image = tm.encode(input_image, payload="example", WM_STRENGTH=1.5) +``` + +## Error correction level + +TrustMark encodes a payload (the watermark data embedded within the image) of 100 bits. +The data schema implemented in `python/datalayer.py` enables you to choose an error correction level over the raw 100 bits of payload to maintain reliability under transformations or noise. + +### Encoding modes + +Set the error correction level using one of the four encoding modes. + +The following table describes TrustMark's encoding modes: + +| Encoding | Protected payload | Number of bit flips allowed | +|----------|-------------------|-----------------------------| +| `Encoding.BCH_5` | 61 bits (+ 35 ECC bits) | 5 | +| `Encoding.BCH_4` | 68 bits (+ 28 ECC bits) | 4 | +| `Encoding.BCH_3` | 75 bits (+ 21 ECC bits) | 3 | +| `Encoding.BCH_SUPER` | 40 bits (+ 56 ECC bits) | 8 | + +Specify the mode when you instantiate the encoder, as follows: + +```py +tm=TrustMark(verbose=True, model_type='Q', encoding_type=TrustMark.Encoding.) +``` + +Where `` is `BCH_5`, `BCH_4`, `BCH_3`, or `BCH_SUPER`. + +For example: + +```py +tm=TrustMark(verbose=True, model_type='Q', encoding_type=TrustMark.Encoding.BCH_5) +``` + +The decoder automatically detects the data schema in a watermark, so you can choose the level of robustness that best suits your use case. + +Selecting the model and strength implicitly selects the level of robustness and visibility of the watermark. If you have reduced robustness for lower visibility, you can regain some robustness by increasing error correction (at the cost of payload capacity). Note that even 40 bits gives a key space of around one trillion. + +## Center cropping + +TrustMark generates residuals at 256 x 256 and then scales/blends them into the original image. Several derivative papers have adopted this universal resolution-scaling trick. + +- If the original image is extremely long/thin (aspect ratio beyond 2:1), the residual watermark will degrade when scaled. +- TrustMark addresses this by automatically center-cropping the image to a square if the aspect ratio exceeds 2.0. For example, for a 1000 x 200 image, only a 200 x 200 region in the center carries the watermark. +- The aspect ratio limit can be overridden via the ASPECT_RATIO_LIM parameter. Setting it to 1.0 always forces center-crop behavior (useful for content platforms that square-crop images). This is the default when using model variant **P**. + +## Do not concentrate watermarks + +Visual quality is often measured via **PSNR** (Peak Signal-to-Noise Ratio), but PSNR does not perfectly correlate with human perception of watermark visibility. + +Some derivative works have tried to improve PSNR by "zero padding" or concentrating the watermark into only the central region, effectively altering fewer pixels and artificially raising the PSNR score. However, this approach **can increase human-visible artifacts** in the concentrated area. + +**Parameter:** CONCENTRATE_WM_REGION +- Default is 100% (no zero padding). +- If you set, for example, 80% zero padding, you might inflate PSNR by ~5 dB. +- At 50% zero padding, PSNR might inflate by ~10 dB. +- In some extreme cases, PSNR can reach 55–60 dB but at the cost of noticeable artifacts in that smaller region. + +**In summary**: While the functionality exists for comparison purposes, it’s not recommended for production. High concentration setting yields high PSNR but paradoxically more visible artifacts in the watermarked area. diff --git a/scripts/fetch-readme.js b/scripts/fetch-readme.js index 7f2d3bc..9769bd8 100644 --- a/scripts/fetch-readme.js +++ b/scripts/fetch-readme.js @@ -196,28 +196,28 @@ const readmes = [ }, // TrustMark { - dest: resolve(__dirname, '../docs/trustmark/readme.md'), - repo: 'adobe/trustmark', + dest: resolve(__dirname, '../docs/trustmark/README.md'), + repo: 'crandmck/trustmark', path: 'README.md', }, { - dest: resolve(__dirname, '../docs/trustmark/config.md'), - repo: 'adobe/trustmark', - path: 'CONFIG.md', + dest: resolve(__dirname, '../docs/trustmark/python/CONFIG.md'), + repo: 'crandmck/trustmark', + path: 'python/CONFIG.md', }, { - dest: resolve(__dirname, '../docs/trustmark/faq.md'), - repo: 'adobe/trustmark', + dest: resolve(__dirname, '../docs/trustmark/FAQ.md'), + repo: 'crandmck/trustmark', path: 'FAQ.md', }, { - dest: resolve(__dirname, '../docs/trustmark/python-readme.md'), - repo: 'adobe/trustmark', - path: 'python/README.md', + dest: resolve(__dirname, '../docs/trustmark/c2pa/README.md'), + repo: 'crandmck/trustmark', + path: 'c2pa/README.md', }, { - dest: resolve(__dirname, '../docs/trustmark/js-readme.md'), - repo: 'adobe/trustmark', + dest: resolve(__dirname, '../docs/trustmark/js/README.md'), + repo: 'crandmck/trustmark', path: 'js/README.md', }, ]; diff --git a/sidebars.js b/sidebars.js index bf2382a..dd0e10f 100644 --- a/sidebars.js +++ b/sidebars.js @@ -277,14 +277,19 @@ const sidebars = { items: [ { type: 'doc', - id: 'trustmark/readme', + id: 'trustmark/README', label: 'Overview', }, { type: 'doc', - id: 'trustmark/config', + id: 'trustmark/python/CONFIG', label: 'Configuration', }, + { + type: 'doc', + id: 'trustmark/c2pa/README', + label: 'Using with C2PA', + }, { type: 'doc', id: 'tm-faq', @@ -292,7 +297,7 @@ const sidebars = { }, { type: 'doc', - id: 'trustmark/js-readme', + id: 'trustmark/js/README', label: 'JavaScript example', }, { From 6ba9995ade366b245e5dc3e8d91e47b890a85fa1 Mon Sep 17 00:00:00 2001 From: Rand McKinney Date: Thu, 20 Mar 2025 15:33:02 -0700 Subject: [PATCH 3/6] Remove file added due to typo in .gitignore --- docs/trustmark/python/CONFIG.md | 100 -------------------------------- 1 file changed, 100 deletions(-) delete mode 100644 docs/trustmark/python/CONFIG.md diff --git a/docs/trustmark/python/CONFIG.md b/docs/trustmark/python/CONFIG.md deleted file mode 100644 index d742b92..0000000 --- a/docs/trustmark/python/CONFIG.md +++ /dev/null @@ -1,100 +0,0 @@ -# Configuring TrustMark - -## Overview - -All watermarking algorithms trade off between three properties: - -- **Capacity (bits)** -- **Robustness (to various transformations)** -- **Visibility (of watermark)** - -This document explains how to configure TrustMark to tune these properties, however the default configuration for TrustMark (variant Q, 100% strength, BCH_5 error correction) is sufficient for most use cases. - -## Model variant - -TrustMark has four model variants (**B**, **C**, **P**, and **Q**) that may be selected when instantiating TrustMark. All encode/decode calls on the object will use this variant. - -In general, we recommend using **P** or **Q**: -- **P** is useful for creative applications where very high visual quality is required. -- **Q** is a good all-rounder and is the default. - -> **Note:** Images encoded with one model variant cannot be decoded with another. - -| Variant | Typical PSNR | Model Size Enc/Dec (MB) | Description | -|---------|--------------|-------------------------|-----------------------------------------------------------------------------------------------------| -| **Q** | 43-45 | 17/45 | Default (**Q**uality). Good trade-off between robustness and imperceptibility. Uses ResNet-50 decoder. | -| **B** | 43-45 | 17/45 | (**B**eta). Very similar to Q, included mainly for reproducing the paper. Uses ResNet-50 decoder. | -| **C** | 38-39 | 17/21 | (**C**ompact). Uses a ResNet-18 decoder (smaller model size). Slightly lower visual quality. | -| **P** | 48-50 | 16/45 | (**P**erceptual). Very high visual quality and good robustness. ResNet-50 decoder trained with much higher weight on perceptual loss (see paper). | - -## Watermark strength - -Set the optional `WM_STRENGTH` parameter when encoding (at runtime). -Its default value is `1.0`, and changing it provides a trade-off between **robustness** and **visibility**: - -- Raising its value (for example, to 1.5) improves robustness (so, for example, the watermark survives printing) but increases the likelihood of ripple artifacts. -- Lowering its value (for example, to 0.8) reduces any likelihood of artifacts but compromises on robustness; however it still survives lower noise, screenshotting, or social media. - -For example: - -```python -encoded_image = tm.encode(input_image, payload="example", WM_STRENGTH=1.5) -``` - -## Error correction level - -TrustMark encodes a payload (the watermark data embedded within the image) of 100 bits. -The data schema implemented in `python/datalayer.py` enables you to choose an error correction level over the raw 100 bits of payload to maintain reliability under transformations or noise. - -### Encoding modes - -Set the error correction level using one of the four encoding modes. - -The following table describes TrustMark's encoding modes: - -| Encoding | Protected payload | Number of bit flips allowed | -|----------|-------------------|-----------------------------| -| `Encoding.BCH_5` | 61 bits (+ 35 ECC bits) | 5 | -| `Encoding.BCH_4` | 68 bits (+ 28 ECC bits) | 4 | -| `Encoding.BCH_3` | 75 bits (+ 21 ECC bits) | 3 | -| `Encoding.BCH_SUPER` | 40 bits (+ 56 ECC bits) | 8 | - -Specify the mode when you instantiate the encoder, as follows: - -```py -tm=TrustMark(verbose=True, model_type='Q', encoding_type=TrustMark.Encoding.) -``` - -Where `` is `BCH_5`, `BCH_4`, `BCH_3`, or `BCH_SUPER`. - -For example: - -```py -tm=TrustMark(verbose=True, model_type='Q', encoding_type=TrustMark.Encoding.BCH_5) -``` - -The decoder automatically detects the data schema in a watermark, so you can choose the level of robustness that best suits your use case. - -Selecting the model and strength implicitly selects the level of robustness and visibility of the watermark. If you have reduced robustness for lower visibility, you can regain some robustness by increasing error correction (at the cost of payload capacity). Note that even 40 bits gives a key space of around one trillion. - -## Center cropping - -TrustMark generates residuals at 256 x 256 and then scales/blends them into the original image. Several derivative papers have adopted this universal resolution-scaling trick. - -- If the original image is extremely long/thin (aspect ratio beyond 2:1), the residual watermark will degrade when scaled. -- TrustMark addresses this by automatically center-cropping the image to a square if the aspect ratio exceeds 2.0. For example, for a 1000 x 200 image, only a 200 x 200 region in the center carries the watermark. -- The aspect ratio limit can be overridden via the ASPECT_RATIO_LIM parameter. Setting it to 1.0 always forces center-crop behavior (useful for content platforms that square-crop images). This is the default when using model variant **P**. - -## Do not concentrate watermarks - -Visual quality is often measured via **PSNR** (Peak Signal-to-Noise Ratio), but PSNR does not perfectly correlate with human perception of watermark visibility. - -Some derivative works have tried to improve PSNR by "zero padding" or concentrating the watermark into only the central region, effectively altering fewer pixels and artificially raising the PSNR score. However, this approach **can increase human-visible artifacts** in the concentrated area. - -**Parameter:** CONCENTRATE_WM_REGION -- Default is 100% (no zero padding). -- If you set, for example, 80% zero padding, you might inflate PSNR by ~5 dB. -- At 50% zero padding, PSNR might inflate by ~10 dB. -- In some extreme cases, PSNR can reach 55–60 dB but at the cost of noticeable artifacts in that smaller region. - -**In summary**: While the functionality exists for comparison purposes, it’s not recommended for production. High concentration setting yields high PSNR but paradoxically more visible artifacts in the watermarked area. From f2acc84566eb96945b3d29d52ffe111a169ad17d Mon Sep 17 00:00:00 2001 From: Rand McKinney Date: Thu, 20 Mar 2025 15:33:20 -0700 Subject: [PATCH 4/6] Fix typo --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 98cb697..a4a171f 100644 --- a/.gitignore +++ b/.gitignore @@ -29,7 +29,7 @@ /docs/trustmark/*.md /docs/trustmark/c2pa/*.md /docs/trustmark/js/*.md -/docs/trustmark/python*.md +/docs/trustmark/python/*.md # Misc .DS_Store From 0114cd6d595819b0df3a12a1e2991c37dc432f4f Mon Sep 17 00:00:00 2001 From: Rand McKinney Date: Thu, 20 Mar 2025 15:44:09 -0700 Subject: [PATCH 5/6] Fix FAQ file case for include --- docs/trustmark-faq.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/trustmark-faq.mdx b/docs/trustmark-faq.mdx index 4cb3667..09b896a 100644 --- a/docs/trustmark-faq.mdx +++ b/docs/trustmark-faq.mdx @@ -47,6 +47,6 @@ hide_table_of_contents: true - [Is TrustMark compatible with blockchain technology?](#is-trustmark-compatible-with-blockchain-technology) - [Can TrustMark be used for NFT provenance?](#can-trustmark-be-used-for-nft-provenance) -import Faq from './trustmark/faq.md'; +import Faq from './trustmark/FAQ.md'; From e93a3e10337725ba8d509d155ff752ecb78d105a Mon Sep 17 00:00:00 2001 From: Rand McKinney Date: Fri, 21 Mar 2025 10:14:47 -0700 Subject: [PATCH 6/6] Change script to get TrustMark docs from Adobe org --- scripts/fetch-readme.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/fetch-readme.js b/scripts/fetch-readme.js index 9769bd8..a3583b1 100644 --- a/scripts/fetch-readme.js +++ b/scripts/fetch-readme.js @@ -197,27 +197,27 @@ const readmes = [ // TrustMark { dest: resolve(__dirname, '../docs/trustmark/README.md'), - repo: 'crandmck/trustmark', + repo: 'adobe/trustmark', path: 'README.md', }, { dest: resolve(__dirname, '../docs/trustmark/python/CONFIG.md'), - repo: 'crandmck/trustmark', + repo: 'adobe/trustmark', path: 'python/CONFIG.md', }, { dest: resolve(__dirname, '../docs/trustmark/FAQ.md'), - repo: 'crandmck/trustmark', + repo: 'adobe/trustmark', path: 'FAQ.md', }, { dest: resolve(__dirname, '../docs/trustmark/c2pa/README.md'), - repo: 'crandmck/trustmark', + repo: 'adobe/trustmark', path: 'c2pa/README.md', }, { dest: resolve(__dirname, '../docs/trustmark/js/README.md'), - repo: 'crandmck/trustmark', + repo: 'adobe/trustmark', path: 'js/README.md', }, ];