Reference

The steganographic embedding in the package can be accessed on three levels of abstraction. This creates a threshold between simplicity and flexibility. For more information, see the glossary.

High-level API

On high-level API, the embedding is a black-box. You pass in the cover image and obtain the stego image.

Currently, there are seven steganography simulators implemented: EBS, F5, HILL, HUGO, J-UNIWARD, LSB, MiPOD, nsF5, S-UNIWARD, UERD and WOW.

Simulators of Spatial Steganography

The spatial steganography operates on pixels.

HILL simulator

conseal.hill.simulate_single_channel(x0: ndarray, alpha: float, *, wet_cost: float = 10000000000, **kw) ndarray

Simulates HILL embedding into a single channel.

HILL was introduced in B. Li, et al. A New Cost Function For Spatial Image Steganography. IEEE ICIP, 2014.

The details of the methods are described in the glossary.

Parameters:
  • x0 (np.ndarray) – uncompressed (pixel) cover image of shape [height, width]

  • alpha (float) – embedding rate in bits per pixel

  • wet_cost (float) – wet cost for unembeddable coefficients

Returns:

stego pixels of shape [height, width, channels]

Return type:

np.ndarray

Example:

>>> x1 = cl.hill.simulate_single_channel(
...     x0=x0,  # cover pixels
...     alpha=.4,  # embedding rate [bpp]
...     seed=12345)  # seed for PSNR

HUGO simulator

conseal.hugo.simulate_single_channel(x0: ndarray, alpha: float, *, sigma: float = 1, gamma: float = 1, wet_cost: float = 100000000.0, **kw) ndarray

Simulates HUGO embedding into a single channel.

HUGO was introduced in T. Pevny, et al. Using High-Dimensional Image Models to Perform Highly Undetectable Steganography. ACM IH, 2010.

The details of the methods are described in the glossary.

Parameters:
  • x0 (np.ndarray) – uncompressed (pixel) cover image of shape [height, width]

  • alpha (float) – embedding rate in bits per pixel

  • wet_cost (float) – wet cost for unembeddable coefficients

  • kw (dict) – remaining keyword parameters are passed to simulator

Returns:

modified stego image of shape [height, width]

Return type:

np.ndarray

Example:

>>> x1 = cl.hugo.simulate_single_channel(
...     x0=x0,  # pixels
...     alpha=0.4,  # alpha
...     seed=12345)  # seed

LSB simulator

conseal.lsb.simulate(cover: ndarray, alpha: float, *, modify: Change = Change.LSB_REPLACEMENT, locate: Optional[Location] = None, permute: Optional[bool] = None, cover_range: Tuple[int] = (0, 255), n: Optional[int] = None, e: float = 2, rhos: Optional[ndarray] = None, wet_cost: float = 10000000000, **kw) ndarray

Simulates LSB steganography at an embedding rate into a cover, and returns stego.

Allows both replacement and matching, sequential and permuted pass. LSB is well-known since early 1990’s.

The details of the methods are described in the glossary.

Parameters:
  • x0 (np.ndarray) – cover image, in pixel or DCT domain, of arbitrary shape

  • alpha (float) – embedding rate in bits per element

  • modify (Change) – modification strategy, replacement by default

  • permute (bool) – permute the changes, otherwise sequential

  • cover_range (tuple) – range of cover values, (0,255) by default

  • n (int) – cover size, used for DCT cover, number of elements by default

  • e (float) – embedding efficiency in bits per change

  • wet_cost (float) – wet cost for unembeddable coefficients

  • kw (dict) – remaining parameters passed to simulator

Returns:

stego image of the same meaning and shape as cover

Return type:

np.ndarray

Example:

>>> x0 = np.array(Image.open('cover.pgm'))
>>> x1 = cl.lsb.simulate(
...   cover=x0,
...   alpha=0.4,
...   modify=cl.LSB_MATCHING,
...   seed=12345)
>>> Image.fromarray(x1).save('stego.pgm')

The function can also take DCT coefficients

>>> jpeg0 = jpeglib.read_dct('cover.jpeg')
>>> jpeg1 = jpeg0.copy()
>>> jpeg1.Y = cl.lsb.simulate(
...   cover=jpeg0.Y,
...   alpha=0.4,
...   modify=cl.LSB_MATCHING,
...   cover_range=(-1024, 1023),
...   seed=12345)
>>> jpeg1.write_dct('stego.jpeg')

Technically, the function can also simulate LSB for color images. This is the reason, why it is called simulate instead of simulate_single_channel.

>>> x0 = np.array(Image.open('cover.ppm'))
>>> x1 = cl.lsb.simulate(
...   cover=x0,
...   alpha=0.4,
...   modify=cl.LSB_MATCHING,
...   seed=12345)
>>> Image.fromarray(x1).save('stego.ppm')
class conseal.lsb.Change(value)

Modify strategy for LSB steganography.

LSB_MATCHING = 2

LSB matching.

LSB_REPLACEMENT = 1

LSB replacement.

class conseal.lsb.Location(value)

Location of embedding changes.

LOCATION_PERMUTED = 1

Permuted embedding.

LOCATION_SELECTED = 3

Selection channel.

LOCATION_SEQUENTIAL = 2

Sequential embedding.

MiPOD simulator

conseal.mipod.simulate_single_channel(x0: ndarray, alpha: float, *, implementation: Implementation = Implementation.MiPOD_FIX_WET, seed: Optional[int] = None) ndarray

Simulates MiPOD steganography.

Parameters:
  • x0 (np.ndarray) – uncompressed (pixel) cover image, of shape [height, width]

  • alpha (float) – embedding rate, in bits per pixel

  • seed (int) – random seed for embedding simulator

Returns:

stego pixels, of shape [height, width, channels]

Return type:

np.ndarray

Example:

>>> x1 = cl.mipod.simulate_single_channel(
...     x0=x0,
...     alpha=.4,
...     seed=12345)
class conseal.mipod.Implementation(value)

MiPOD implementation to choose from.

MiPOD_FIX_WET = 2

MiPOD implementation with wet-cost fixes.

MiPOD_ORIGINAL = 1

Original MiPOD implementation by Remi Cogranne.

S-UNIWARD simulator

conseal.suniward.simulate_single_channel(x0: ndarray, alpha: float, *, sigma: float = 1, wet_cost: float = 100000000, **kw) ndarray

Simulates S-UNIWARD embedding into a single channel.

Parameters:
  • x0 (np.ndarray) – uncompressed (pixel) cover image, of shape [height, width]

  • alpha (float) – embedding rate, in bits per pixel

  • sigma (float) – stabilizing constant. Small sigmas make the embedding very sensitive to the image content. Large sigmas smooth out the embedding change probabilities.

  • wet_cost (float) – cost for unembeddable coefficients

Returns:

stego pixels, of shape [height, width, channels]

Return type:

np.ndarray

Example:

>>> x1 = cl.suniward.simulate_single_channel(
...   x0=x0,  # pixels
...   alpha=0.4,  # embedding rate
...   seed=12345)  # seed

WOW simulator

conseal.wow.simulate_single_channel(x0: ndarray, alpha: float, *, p: float = -1, wet_cost: float = 100000000, **kw) ndarray

Simulates WOW embedding into a single channel.

Parameters:
  • x0 (np.ndarray) – uncompressed (pixel) cover image, of shape [height, width]

  • alpha (float) – embedding rate, in bits per pixel

  • p (float) – parameter for reciprocal Hoelder norm.

  • wet_cost (float) – cost for unembeddable coefficients

Returns:

stego pixels, of shape [height, width, channels]

Return type:

np.ndarray

Example:

>>> x1 = cl.wow.simulate_single_channel(
...   x0=x0,  # pixels
...   alpha=0.4,  # embedding rate
...   seed=12345)  # seed

Simulators of JPEG Steganography

The JPEG steganography operates on DCT coefficients. To learn on how to acquire them, see the glossary.

EBS simulator

conseal.ebs.simulate_single_channel(y0: ndarray, qt: ndarray, alpha: float, *, wet_cost: float = 10000000000000, implementation: Implementation = Implementation.EBS_ORIGINAL, generator: str = 'MT19937', order: str = 'C', seed: Optional[int] = None) ndarray

Simulates EBS embedding at an embedding rate into single-channel cover, and returns stego.

EBS was introduced in C. Wang, et al. An efficient JPEG steganographic scheme based on block entropy of DCT coefficients. IEEE ICASSP, 2012.

The details of the methods are described in the glossary.

Parameters:
  • y0 (np.ndarray) – quantized cover DCT coefficients of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

  • qt (np.ndarray) – quantization table of shape [8, 8]

  • alpha (float) – embedding rate in bits per nzAC coefficient

  • wet_cost (float) – wet cost for unembeddable coefficients

  • implementation (Implementation) – choose EBS implementation

  • generator (numpy.random.Generator) – type of PRNG used by embedding simulator

  • seed (int) – random seed for embedding simulator

Returns:

quantized stego DCT coefficients of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

Return type:

np.ndarray

Example:

>>> im_dct.Y = cl.ebs.simulate_single_channel(
...   y0=im_dct.Y,      # DCT
...   qt=im_dct.qt[0],  # QT
...   alpha=0.4,        # alpha
...   seed=12345)       # seed
class conseal.ebs.Implementation(value)

EBS implementation to choose from.

EBS_FIX_WET = 2

EBS implementation with wet-cost fixes in not-SI case.

EBS_ORIGINAL = 1

Original EBS implementation by Remi Cogranne.

F5 simulator

conseal.F5.simulate_single_channel(*args, **kw) ndarray

Simulates F5 embedding at an embedding rate at an embedding rate into single-channel cover and returns stego.

This is done by simulating nsF5 first, and then re-introducing the shrinkage.

Returns:

quantized stego DCT coefficients of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

Return type:

np.ndarray

Example:

>>> im_dct.Y = cl.F5.simulate_single_channel(
...   y0=im_dct.Y,  # DCT
...   alpha=0.4,  # alpha
...   seed=12345)  # seed

J-UNIWARD simulator

conseal.juniward.simulate_single_channel(x0: ~numpy.ndarray, y0: ~numpy.ndarray, qt: ~numpy.ndarray, alpha: float, *, wet_cost: float = 10000000000000, dtype: ~numpy.dtype = <class 'numpy.float64'>, implementation: ~conseal.juniward._costmap.Implementation = Implementation.JUNIWARD_ORIGINAL, generator: ~typing.Optional[str] = None, seed: ~typing.Optional[int] = None) ndarray

Simulates J-UNIWARD embedding at an embedding rate into single-channel cover, and returns stego.

J-UNIWARD was introduced in V. Holub, et al. Universal distortion function for steganography in an arbitrary domain. EURASIP JIS, 2014.

The details of the methods are described in the glossary.

Parameters:
  • x0 (np.ndarray) – decompressed (pixel) cover image of shape [height, width]

  • y0 (np.ndarray) – quantized cover DCT coefficients of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

  • qt (np.ndarray) – quantization table of shape [8, 8]

  • alpha (float) – embedding rate in bits per nzAC coefficient

  • wet_cost (float) – wet cost for unembeddable coefficients

  • dtype (np.dtype) – data type to use for distortion computation, float64 by default

  • implementation (Implementation) – choose J-UNIWARD implementation

  • generator (numpy.random.Generator) – type of PRNG used by embedding simulator

  • seed (int) – random seed for embedding simulator

Returns:

quantized stego DCT coefficients of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

Return type:

np.ndarray

Example:

>>> jpeg1.Y = cl.juniward.simulate_single_channel(
...   y0=jpeg0.Y,  # DCT
...   qt=jpeg0.qt[0],  # QT
...   x0=im0.spatial[..., 0],  # decompressed
...   alpha=0.4,  # embedding rate
...   seed=12345)  # seed
class conseal.juniward.Implementation(value)

J-UNIWARD implementation to choose from.

JUNIWARD_FIX_OFF_BY_ONE = 2

J-UNIWARD implementation with fixed off-by-one error.

See https://arxiv.org/pdf/2305.19776.pdf for more details.

JUNIWARD_ORIGINAL = 1

Original J-UNIWARD implementation.

nsF5 simulator

conseal.nsF5.simulate_single_channel(y0: ndarray, alpha: float, *, add_shrinkage: bool = False, e: Optional[float] = None, seed: Optional[int] = None) ndarray

Simulates nsF5 embedding at an embedding rate into single-channel cover and returns stego.

nsF5 was introduced in J. Fridrich, et al. Statistically undetectable JPEG steganography: Dead ends, challenges, and opportunities. ACM MMSec, 2007.

The details of the methods are described in the glossary.

Parameters:
  • y0 (np.ndarray) – quantized cover DCT coefficients of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

  • alpha (float) – embedding rate

  • e – embedding efficiency in bits per change

  • seed (int) – random seed for embedding simulator

Returns:

quantized stego DCT coefficients, of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

Return type:

np.ndarray

Example:

>>> im_dct.Y = cl.nsF5.simulate_single_channel(
...   y0=im_dct.Y,  # DCT
...   alpha=0.4,  # alpha
...   seed=12345)  # seed

UERD simulator

conseal.uerd.simulate_single_channel(y0: ndarray, qt: ndarray, alpha: float, *, payload_mode: str = 'bpnzAC', wet_cost: float = 10000000000000, seed: Optional[int] = None) ndarray

Simulates UERD embedding at an embedding rate into single-channel cover, and returns stego.

UERD was introduced in L. Guo, et al. Using Statistical Image Model for JPEG Steganography: Uniform Embedding Revisited. IEEE TIFS, 2015.

The details of the methods are described in the glossary.

Parameters:
  • y0 (np.ndarray) – quantized DCT coefficients of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

  • qt (np.ndarray) – quantized table of shape [8, 8]

  • alpha (float) – embedding rate, in unit specified by payload_mode

  • payload_mode (str) – unit used by embedding rate, either “bpc” (bits per DCT coefficient), or “bpnzAC” (bits per non-zero DCT AC coefficient).

  • wet_cost (float) – wet cost for unembeddable coefficients

  • seed (int) – random seed for embedding simulator

Returns:

stego DCT coefficients of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

Return type:

np.ndarray

Example:

>>> im_dct.Y = cl.uerd.simulate_single_channel(
...   y0=im_dct.Y,  # DCT
...   qt=im_dct.qt[0],  # QT
...   alha=0.4,  # alpha
...   seed=12345)  # seed

Mid-level API

On mid-level API, you separately compute the cost (automatically adjusted for wet elements already), and run the simulator.

Adjusted cost

EBS adjusted cost

conseal.ebs.compute_cost_adjusted(y0: ndarray, qt: ndarray, *, x0: Optional[ndarray] = None, theta: float = 2, implementation: Implementation = Implementation.EBS_FIX_WET, wet_cost: float = 10000000000000) ndarray

Computes the costmap and prepares the costmap for ternary embedding.

Parameters:
  • y0 (np.ndarray) – quantized cover DCT coefficients of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

  • qt (np.ndarray) – quantization table of shape [8, 8]

  • x0 – precover for rounding error computation of shape [num_vertical_blocks*8, num_horizontal_blocks*8]

  • theta (float) – cost parameter, 2 by default (from paper)

  • implementation (Implementation) – choose EBS implementation

  • wet_cost (float) – cost for unembeddable coefficients

Returns:

probability maps for +1 and -1 changes of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

Return type:

tuple of np.ndarray

Example:

>>> (rho_p1, rho_m1) = cl.ebs.compute_cost_adjusted(
...   y0=im_dct.Y,  # DCT
...   qt=im_dct.qt[0])  # QT
>>> im_dct.Y += cl.simulate.ternary(
...   rhos=(rho_p1, rho_m1)  # costs of +1 and -1 changes
...   alpha=0.4,  # alpha
...   n=im_dct.Y.size,  # cover size
...   seed=12345)  # seed

HILL adjusted cost

conseal.hill.compute_cost_adjusted(x0: ndarray, *, wet_cost: float = 10000000000.0) Tuple[ndarray]

Computes HILL cost with wet-cost adjustments.

Parameters:
  • x0 (np.ndarray) – uncompressed (pixel) cover image of shape [height, width]

  • wet_cost (float) – wet cost for unembeddable coefficients

Returns:

costs for +1 and -1 changes of shape [height, width]

Return type:

np.ndarray

Example:

>>> rhos = cl.hill.compute_cost_adjusted(x0=x0)

HUGO adjusted cost

conseal.hugo.compute_cost_adjusted(x0: ndarray, *, sigma: float = 1, gamma: float = 1, wet_cost: float = 100000000.0)

Computes HUGO cost with wet-cost adjustments.

Parameters:
  • x0 (np.ndarray) – uncompressed (pixel) cover image of shape [height, width]

  • sigma (float) – additive parameter

  • gamma (float) – exponent parameter

  • wet_cost (float) – wet cost for unembeddable coefficients

Returns:

costs for +1 and -1 changes

Return type:

tuple of np.ndarray

Example:

>>> # TODO

J-UNIWARD adjusted cost

conseal.juniward.compute_cost_adjusted(x0: ~numpy.ndarray, y0: ~numpy.ndarray, qt: ~numpy.ndarray, *, dtype: ~numpy.dtype = <class 'numpy.float64'>, implementation: ~conseal.juniward._costmap.Implementation = Implementation.JUNIWARD_ORIGINAL, wet_cost: float = 10000000000000, avoid_saturated: bool = False) Tuple[ndarray, ndarray]

Compute the adjusted J-UNIWARD cost for a ternary embedding.

Parameters:
  • x0 (np.ndarray) – decompressed (pixel) image, of shape [height, width]

  • y0 (np.ndarray) – quantized cover DCT coefficients, of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

  • qt (np.ndarray) – quantization table, of shape [8, 8]

  • dtype (np.dtype) – data type to use for distortion computation, float64 by default

  • implementation (Implementation) – choose J-UNIWARD implementation

  • wet_cost (float) – cost for unembeddable coefficients

  • avoid_saturated (bool) – hard-sets blocks with saturated pixels to wet

Returns:

embedding costs of +1 and -1 changes, of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

Return type:

tuple of np.ndarray

Example:

>>> rho_p1, rho_m1 = cl.juniward._costmap.compute_cost_adjusted(
...     y0=jpeg0.Y,      # DCT
...     qt=jpeg0.qt[0],  # QT
...     x0=im0.spatial)  # decompressed spatial
>>> im_dct.Y += cl.simulate.ternary(
...     rhos=(rho_p1, rho_m1),  # distortion of +1 and -1 change
...     alpha=0.4,              # alpha
...     n=im_dct.Y.size,        # cover size
...     seed=12345)             # seed

LSB adjusted cost

conseal.lsb.compute_cost_adjusted(cover: ndarray, *, modify: Change = Change.LSB_REPLACEMENT, cover_range: Tuple[int] = (0, 255), wet_cost: float = 10000000000) ndarray

Returns LSB distortion.

Provides unified interface with distortion-based embeddings.

Parameters:
  • cover (np.ndarray) – cover image, in pixel or DCT domain, of arbitrary shape

  • modify (Change) – modification strategy, replacement by default

  • cover_range (tuple) – Range of cover values, (0,255) by default.

  • wet_cost (float) – wet cost for unembeddable elements

Returns:

distortion of the same shape as cover

Return type:

np.ndarray

Example:

>>> rhos = cl.lsb.compute_cost_adjusted(x0)
>>> x1 = x0 + cl.simulate.ternary(rhos=rhos, alpha=.4, seed=12345)

nsF5 adjusted cost

conseal.nsF5.compute_cost_adjusted(y0: ndarray, *, wet_cost: float = 10000000000) Tuple[ndarray]

Compute nsF5 cost with wet-cost adjustments.

Parameters:
  • y0 (np.ndarray) – quantized cover DCT coefficients, of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

  • wet_cost (float) – wet cost for unembeddable coefficients

Returns:

probability of +-1 change, of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

Return type:

tuple of np.ndarray

Example:

>>> rhos = cl.nsF5.compute_cost_adjusted(jpeg0.Y)
>>> jpeg1.Y = jpeg0.Y + cl.simulate.ternary(rhos=rhos, alpha=.4, seed=12345)

S-UNIWARD adjusted cost

conseal.suniward.compute_cost_adjusted(x0: ndarray, *, wet_cost: float = 100000000, **kw) Tuple[ndarray, ndarray]

Computes S-UNIWARD cost with wet-cost adjustments.

Parameters:
  • x0 (np.ndarray) – uncompressed (pixel) cover image, of shape [height, width]

  • wet_cost (float) – wet cost for unembeddable coefficients

Returns:

costs for +1 and -1 changes, of shape [height, width]

Return type:

np.ndarray

Example:

>>> rhos = cl.suniward.compute_cost_adjusted(x0=x0)

UERD adjusted cost

conseal.uerd.compute_cost_adjusted(y0: ndarray, qt: ndarray, *, wet_cost: float = 10000000000000, avoid_saturated: bool = False) Tuple[ndarray, ndarray]

Compute the adjusted J-UNIWARD cost for ternary embedding.

Parameters:
  • y0 (np.ndarray) – quantized cover DCT coefficients, of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

  • qt (np.ndarray) – quantization table, of shape [8, 8]

  • wet_cost (float) – cost for unembeddable coefficients

  • avoid_saturated (bool) – hard-sets blocks with saturated pixels to wet

Returns:

embedding costs of +1 and -1 changes, of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

Return type:

tuple of np.ndarray

Example:

>>> rho_p1, rho_m1 = cl.uerd.compute_cost_adjusted(
...   y0=jpeg0.Y,      # DCT
...   qt=jpeg0.qt[0])  # QT

WOW adjusted cost

conseal.wow.compute_cost_adjusted(x0: ndarray, wet_cost: float = 10000000000.0, **kw) Tuple[ndarray]

Computes WOW cost with wet-cost adjustments.

Parameters:
  • x0 (np.ndarray) – uncompressed (pixel) cover image, of shape [height, width]

  • wet_cost (float) – wet cost for unembeddable coefficients

Returns:

costs for +1 and -1 changes, of shape [height, width]

Return type:

np.ndarray

Example:

>>> rhos = cl.wow.compute_cost_adjusted(x0=x0)

Mid-level Simulator API

conseal.simulate.ternary(rhos: Tuple[ndarray], alpha: float, n: int, *, e: Optional[float] = None, objective: Optional[Callable] = None, sender: Sender = Sender.PAYLOAD_LIMITED_SENDER, **kw) ndarray

Simulates ternary embedding given distortion and embedding rate.

Parameters:
  • rhos (tuple of np.ndarray) – costs for +1 and -1 changes of an arbitrary shape

  • alpha (float) – embedding rate in bits per element

  • n (int) – cover size

  • objective

Returns:

Simulated difference image to be added to the cover, 0 (keep), 1 or -1 (change).

Return type:

np.ndarray

Example:

>>> rho_p1, rho_m1 = cl.uerd.compute_cost_adjusted(
...   cover_dct_coeffs=im_dct.Y,  # DCT
...   quantization_table=im_dct.qt[0])  # QT
>>> im_dct.Y += cl.simulate.ternary(
...   rhos=(rho_p1, rho_m1),  # cost of +1 and -1 change
...   alpha=0.4,  # alpha
...   n=im_dct.Y.size,  # cover size
...   seed=12345)  # seed
conseal.simulate.binary(rhos: Tuple[ndarray], alpha: float, n: int, *, e: Optional[float] = None, objective: Optional[Callable] = None, sender: Sender = Sender.PAYLOAD_LIMITED_SENDER, **kw) ndarray

Simulates binary embedding given distortion and embedding rate.

Parameters:
  • rhos (tuple of np.ndarray) – cost for +-1 changes, of an arbitrary shape

  • alpha (float) – embedding rate, in bits per element

  • n (int) – cover size/number of cover elements

  • objective (callable) – Objective function to maximize. Entropy by default

Returns:

Simulated difference image to be added to the cover, 0 (keep), 1 or -1 (change).

Return type:

np.ndarray

Example:

>>> (rho_pm1,) = cl.uerd.compute_cost_adjusted(
...   cover_dct_coeffs=im_dct.Y,  # DCT
...   quantization_table=im_dct.qt[0])  # QT
>>> im_dct.Y += cl.simulate.binary(
...   rhos=(rho_pm1,),  # cost of +-1 change
...   alpha=0.4,  # alpha
...   n=im_dct.Y.size,  # cover size
...   seed=12345)  # seed

Steganographic coding

The simulator can be modified by incorporating coding-specific features.

conseal.coding.efficiency(alpha: float) float

Calculates the embedding efficiency at the bound.

Parameters:

alpha (float) – embedding rate, at bits per element

Returns:

embedding efficiency, at bits per element

Return type:

float

Example:

>>> e = cl.coding.efficiency(0.4)  # e at alpha=0.4

Hamming codes

conseal.coding.hamming.efficiency(alpha: float) float

Approximates embedding efficiency for Hamming code.

Assumes last block to be padded.

Parameters:

alpha (float) – embedding rate in bits per element

Returns:

embedding efficiency in bits per change

Return type:

float

Example:

>>> e = cl.coding.efficiency(0.4)  # e at alpha=0.4

Wet-paper codes

conseal.coding.wpc.generate_H(m: int, n: Optional[int] = None, *, c: float = 0.1, delta: float = 0.5, seed: Optional[int] = None) ndarray

Generates parity-check matrix according to robust soliton distribution.

Parameters:
  • m (int) – number of rows/message bits

  • n (int) – number of columns/cover elements

  • c (float) – constant parameter, 0.1 by default

  • delta (float) – failure probability, 0.5 by default

Returns:

generated parity-check matrix

Return type:

np.ndarray

Example:

>>> H = generate_H(50, delta=.5, c=.1, seed=12345)

Other utilities

conseal.tools.nzAC(dct: ndarray) int

Computes number of non-zero DCT AC coefficients from 4D DCT tensor.

Parameters:

dct (np.ndarray) – array of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

Returns:

number of non-zero DCT AC coefficients

Return type:

int

Example:

>>> cl.tools.nzAC(jpeg0.Y)
conseal.tools.AC(dct: ndarray) int

Computes number of DCT AC coefficients from 4D DCT tensor.

Parameters:

dct (np.ndarray) – array of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

Returns:

number of DCT AC coefficients

Return type:

int

Example:

>>> cl.tools.AC(jpeg0.Y)
conseal.tools.permute.password_to_seed(password: str) int

Converts password to seed for random generator.

Parameters:
  • password (str) – string password

  • seed (int) – random seed for embedding simulator

Example:

>>> seed = cl.tools.password_to_seed(cover_name)  # cover-specific seed
>>> rng = np.random.default_rng(seed)

Low-level API

On the low-level API, you can access the raw cost (without wet-pixel adjustment), the probability calculation (together with the lambda parameter), and the simulator which takes the probabilities.

Raw cost

EBS cost

conseal.ebs._costmap.compute_cost(y0: ndarray, qt: ndarray, *, rounding_error: Optional[ndarray] = None, theta: float = 2) ndarray

Compute EBS cost.

Near-equivalent to Remi Cogranne’s implementation. The difference comes from numerical difference in log/np.log.

Parameters:
  • y0 (np.ndarray) –

  • qt

  • rounding_error

  • theta (float) – distortion parameter, 2 by default (from paper)

Returns:

Return type:

np.ndarray

Example:

>>> # TODO

HILL cost

conseal.hill._costmap.compute_cost(x0: ndarray) ndarray

Computes HILL cost.

Parameters:

x0 (np.ndarray) – uncompressed (pixel) cover image of shape [height, width]

Returns:

cost for +-1 change of shape [height, width]

Return type:

np.ndarray

Example:

>>> rho = cl.hill.compute_cost(x0=x0)

HUGO cost

conseal.hugo._costmap.compute_cost(x0: ndarray, x0_padded: ndarray, sigma: float = 1, gamma: float = 1) Tuple[ndarray]

Computes HUGO cost.

Unlike most other distortions, HUGO is truly directional.

Parameters:
  • x0 (np.ndarray) – uncompressed (pixel) cover image of shape [height, width]

  • x0_padded (np.ndarray) –

  • sigma (float) – parameter

  • gamma (float) – parameter

Returns:

cost of the same shape as cover

Return type:

np.ndarray

Example:

>>> # TODO

J-UNIWARD cost

conseal.juniward._costmap.compute_cost(x0: ~numpy.ndarray, qt: ~numpy.ndarray, *, sigma: float = 0.015625, dtype: ~numpy.dtype = <class 'numpy.float64'>, implementation: ~conseal.juniward._costmap.Implementation = Implementation.JUNIWARD_ORIGINAL) ndarray

Compute the J-UNIWARD cost.

Parameters:
  • x0 (np.ndarray) – decompressed (pixel) image of shape [height, width]

  • qt (np.ndarray) – quantization table of shape [8, 8]

  • sigma (float) – parameter controlling the content sensitivity, avoids division by zero but also controls the sensitivity to content.

  • dtype (np.ndarray) – data type to use for distortion computation, float64 by default

  • implementation (Implementation) – choose J-UNIWARD implementation

Returns:

embedding cost of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

Return type:

np.ndarray

Example:

>>> # TODO

LSB cost

conseal.lsb._costmap.compute_cost(cover: ndarray, *, modify: Change = Change.LSB_REPLACEMENT, wet_cost: float = 10000000000) ndarray

Returns LSB cost.

Provides unified interface with cost-based embeddings.

Parameters:
  • cover (np.ndarray) – cover image, in pixel or DCT domain, of arbitrary shape

  • modify (Change) – modification strategy, replacement by default

  • cover_range (tuple) – Range of cover values, (0,255) by default.

  • wet_cost (float) – wet cost for unembeddable elements

Returns:

cost of the same shape as cover

Return type:

np.ndarray

Example:

>>> # TODO

nsF5 cost

conseal.nsF5._costmap.compute_cost(y0: ndarray, *, wet_cost: float = 10000000000) ndarray

Compute the nsF5 cost.

Parameters:
  • y0 (np.ndarray) – quantized cover DCT coefficients, of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

  • wet_cost (float) – wet cost for unembeddable coefficients

Returns:

probability of +-1 change, of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

Return type:

tuple of np.ndarray

Example:

>>> # TODO

S-UNIWARD cost

conseal.suniward._costmap.compute_cost(x0: ndarray, *, sigma: float = 1, filters: Optional[List[ndarray]] = None) ndarray

Computes S-UNIWARD cost.

Parameters:
  • x0 (np.ndarray) – uncompressed (pixel) cover image, of shape [height, width]

  • sigma (float) – stabilizing constant. Small sigmas make the embedding very sensitive to the image content. Large sigmas smooth out the embedding change probabilities.

  • filters – filters to use, by default Daubechies8 wavelet

Returns:

cost for +-1 change, of shape [height, width]

Return type:

np.ndarray

Example:

>>> # TODO

UERD cost

conseal.uerd._costmap.compute_cost(y0: ndarray, qt: ndarray) ndarray

Compute the UERD cost.

Check Eq. 4 of the paper.

Parameters:
  • y0 (np.ndarray) – quantized cover DCT coefficients, of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

  • qt (np.ndarray) – quantization table, of shape [8, 8]

Returns:

embedding cost, of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

Return type:

np.ndarray

Example:

>>> # TODO

WOW cost

conseal.wow._costmap.compute_cost(x0: ndarray, *, p: float = -1) Tuple[ndarray]

Computes WOW cost.

Parameters:
  • x0 (np.ndarray) – uncompressed (pixel) cover image, of shape [height, width]

  • p (float) – parameter for reciprocal Hoelder norm

Returns:

cost for +-1 change, of shape [height, width]

Return type:

np.ndarray

Example:

>>> # TODO

Probability

nsF5 probability

conseal.nsF5._costmap.probability(y0: ndarray, alpha: float) ndarray

Compute the nsF5 probability map.

Parameters:
  • y0 (np.ndarray) – quantized cover DCT coefficients, of shape [num_vertical_blocks, num_horizontal_blocks, 8, 8]

  • alpha (float) – embedding rate, in bits per nzAC coefficient

Returns:

tuple ((p_p1, p_m1), None), where p_p1 is the probability of +1 change p_m1 is the probability of -1 change.

Return type:

tuple of np.ndarray

Example:

>>> # TODO

LSB probability

conseal.lsb._costmap.probability(cover: ndarray, alpha: float, *, modify: Change = Change.LSB_REPLACEMENT, locate: Optional[Location] = None, permute: Optional[bool] = None, cover_range: Tuple[int] = (0, 255), n: Optional[int] = None, rhos: Optional[array] = None, e: float = 2, wet_cost: float = 10000000000) ndarray

Returns LSB probability map for consequent simulation.

Parameters:
  • cover (np.ndarray) – cover image of arbitrary shape in pixel or DCT domain

  • alpha (float) – embedding rate in bits per pixel

  • modify (Change) – modification strategy, replacement by default

  • permute (bool) – Permute the changes, otherwise sequential

  • cover_range (tuple) – Range of cover values, (0,255) by default.

  • n (int) – cover size, used for DCT cover, number of elements by default

  • e (float) – embedding efficiency in bits per change

  • rhos (np.ndarray) – costs for the selection channel

  • wet_cost (float) – wet cost for unembeddable elements

Returns:

probability map of the same shape as cover

Return type:

np.ndarray

Example:

>>> ps, _ = cl.lsb.probability(x0, alpha=.4)
>>> x1 = x0 + cl.simulate._ternary.simulate(ps=ps, seed=12345)

Low-level Simulator API

conseal.simulate._ternary.probability(rhos: Tuple[ndarray], alpha: float, n: int, *, e: Optional[float] = None, objective: Optional[Callable] = None, sender: Sender = Sender.PAYLOAD_LIMITED_SENDER) Tuple[ndarray, float]

Convert binary distortion to binary probability.

Parameters:
  • rhos (tuple of np.ndarray) – distortion tensor for +1 and -1 change

  • alpha (float) – embedding rate in bits per element, generally a constraint for the specified sender type

  • n (int) – cover size/number of cover elements

  • e (float) – embedding efficiency in bits per element, optimal coding assumed by default

  • objective (callable) – objective function to maximize, entropy by default

Returns:

tuple ((p_p1, p_m1), lmbda), where p_p1 is the probability of +1 change, p_m1 is the probability of -1 change, and lbda is the determined lambda.

Return type:

tuple

Example:

>>> (p_p1, p_m1), lbda = cl.simulate._ternary.probability(
...   rhos=(rho_p1, rho_m1),  # costs for +1 and -1
...   alpha=0.4,              # embedding rate, 0.4 message bits per element
...   n=im_dct.Y.size)        # cover size
>>> im_dct.Y += cl.simulate._ternary.simulate(
...   ps=(p_p1, p_m1),  # probability of +1 and -1
...   seed=12345)       # seed
conseal.simulate._ternary.simulate(ps: Tuple[ndarray], generator: Optional[str] = None, order: str = 'C', seed: Optional[int] = None) ndarray

Simulates changes using the given probability maps.

Parameters:
  • ps (tuple of np.ndarray) – probability tensors for +1 and -1 changes, of an arbitrary shape

  • generator (str) – random number generator to choose, None (numpy default) or ‘MT19937’ (used by Matlab)

  • order (str) – order of changes, ‘C’ (C-order, column-row) or ‘F’ (F-order, row-column).

  • seed (int) – random seed for embedding simulator

Returns:

Simulated ternary changes in the cover, 0 (keep), +1 or -1.

Return type:

np.ndarray

Example:

>>> (p_p1, p_m1), lbda = cl.simulate._ternary.probability(
...   rhos=(rho_p1, rho_m1),  # distortion of +1 and -1 changes
...   alpha=0.4,  # alpha
...   n=im_dct.Y.size)  # cover size
>>> im_dct.Y += cl.simulate._ternary.simulate(
...   ps=(p_p1, p_m1),  # probability of +1 and -1 changes
...   seed=12345)  # seed