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:
- 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:
- 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 defaultpermute (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:
- 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')
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:
- Example:
>>> x1 = cl.mipod.simulate_single_channel( ... x0=x0, ... alpha=.4, ... seed=12345)
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:
- 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:
- 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 implementationgenerator (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:
- 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
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:
- 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 implementationgenerator (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:
- 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:
- 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:
- 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 implementationwet_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:
- 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 implementationwet_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 defaultcover_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:
- 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:
- 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:
- 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:
- 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:
- 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:
- 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:
- 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:
- Returns:
generated parity-check matrix
- Return type:
- 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:
- 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:
- Example:
>>> cl.tools.AC(jpeg0.Y)
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:
- 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:
- 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:
- 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:
- 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 defaultcover_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:
- 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:
- 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:
- 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:
- 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 defaultpermute (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:
- 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:
- 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:
- 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