Giter VIP home page Giter VIP logo

invisible-watermark's Introduction

invisible-watermark

PyPI License Python Platform Downloads

invisible-watermark is a python library and command line tool for creating invisible watermark over image (a.k.a. blink image watermark, digital image watermark). The algorithm doesn't rely on the original image.

Note that this library is still experimental and it doesn't support GPU acceleration, carefully deploy it on the production environment. The default method dwtDCT(one variant of frequency methods) is ready for on-the-fly embedding, the other methods are too slow on a CPU only environment.

supported algorithms

speed

  • default embedding method dwtDct is fast and suitable for on-the-fly embedding
  • dwtDctSvd is 3x slower and rivaGan is 10x slower, for large image they are not suitable for on-the-fly embedding

accuracy

  • The algorithm cannot guarantee to decode the original watermarks 100% accurately even though we don't apply any attack.
  • Known defects: Test shows all algorithms do not perform well for web page screenshots or posters with homogenous background color

Supported Algorithms

  • dwtDct: DWT + DCT transform, embed watermark bit into max non-trivial coefficient of block dct coefficents

  • dwtDctSvd: DWT + DCT transform, SVD decomposition of each block, embed watermark bit into singular value decomposition

  • rivaGan: encoder/decoder model with Attention mechanism + embed watermark bits into vector.

background:

How to install

pip install invisible-watermark

Embed watermark

  • example embed 4 characters (32 bits) watermark
import cv2
from imwatermark import WatermarkEncoder

bgr = cv2.imread('test.png')
wm = 'test'

encoder = WatermarkEncoder()
encoder.set_watermark('bytes', wm.encode('utf-8'))
bgr_encoded = encoder.encode(bgr, 'dwtDct')

cv2.imwrite('test_wm.png', bgr_encoded)

Decode watermark

  • example decode 4 characters (32 bits) watermark
import cv2
from imwatermark import WatermarkDecoder

bgr = cv2.imread('test_wm.png')

decoder = WatermarkDecoder('bytes', 32)
watermark = decoder.decode(bgr, 'dwtDct')
print(watermark.decode('utf-8'))

CLI Usage

embed watermark:  ./invisible-watermark -v -a encode -t bytes -m dwtDct -w 'hello' -o ./test_vectors/wm.png ./test_vectors/original.jpg

decode watermark: ./invisible-watermark -v -a decode -t bytes -m dwtDct -l 40 ./test_vectors/wm.png

positional arguments:
  input                 The path of input

optional arguments:
  -h, --help            show this help message and exit
  -a ACTION, --action ACTION
                        encode|decode (default: None)
  -t TYPE, --type TYPE  bytes|b16|bits|uuid|ipv4 (default: bits)
  -m METHOD, --method METHOD
                        dwtDct|dwtDctSvd|rivaGan (default: maxDct)
  -w WATERMARK, --watermark WATERMARK
                        embedded string (default: )
  -l LENGTH, --length LENGTH
                        watermark bits length, required for bytes|b16|bits
                        watermark (default: 0)
  -o OUTPUT, --output OUTPUT
                        The path of output (default: None)
  -v, --verbose         print info (default: False)

Test Result

For better doc reading, we compress all images in this page, but the test is taken on 1920x1080 original image.

Methods are not robust to resize or aspect ratio changed crop but robust to noise, color filter, brightness and jpg compress.

rivaGan outperforms the default method on crop attack.

only default method is ready for on-the-fly embedding.

Input

  • Input Image: 1960x1080 Image
  • Watermark:
    • For freq method, we use 64bits, string expression "qingquan"
    • For RivaGan method, we use 32bits, string expression "qing"
  • Parameters: only take U frame to keep image quality, scale=36

Attack Performance

Watermarked Image

wm

Attacks Image Freq Method RivaGan
JPG Compress wm_jpg Pass Pass
Noise wm_noise Pass Pass
Brightness wm_darken Pass Pass
Overlay wm_overlay Pass Pass
Mask wm_mask_large Pass Pass
crop 7x5 wm_crop_7x5 Fail Pass
Resize 50% wm_resize_half Fail Fail
Rotate 30 degress wm_rotate Fail Fail

Running Speed (CPU Only)

Image Method Encoding Decoding
1920x1080 dwtDct 300-350ms 150ms-200ms
1920x1080 dwtDctSvd 1500ms-2s ~1s
1920x1080 rivaGan ~5s 4-5s
600x600 dwtDct 70ms 60ms
600x600 dwtDctSvd 185ms 320ms
600x600 rivaGan 1s 600ms

RivaGAN Experimental

Further, We will deliver the 64bit rivaGan model and test the performance on GPU environment.

Detail: https://github.com/DAI-Lab/RivaGAN

Zhang, Kevin Alex and Xu, Lei and Cuesta-Infante, Alfredo and Veeramachaneni, Kalyan. Robust Invisible Video Watermarking with Attention. MIT EECS, September 2019.[PDF]

invisible-watermark's People

Contributors

buley avatar eltociear avatar patrickvonplaten avatar qingquanwang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

invisible-watermark's Issues

Run with GPU

We can run the code on the GPU with the following modifications:

pip install onnxruntime-gpu

Modify the following code segment in ./imwatermark/rivaGAN.py

RivaWatermark.encoder = onnxruntime.InferenceSession(
    os.path.join(modelDir, 'rivagan_encoder.onnx'))
RivaWatermark.decoder = onnxruntime.InferenceSession(
    os.path.join(modelDir, 'rivagan_decoder.onnx'))

to

RivaWatermark.encoder = onnxruntime.InferenceSession(
    os.path.join(modelDir, 'rivagan_encoder.onnx'), providers=['CUDAExecutionProvider'])
RivaWatermark.decoder = onnxruntime.InferenceSession(
    os.path.join(modelDir, 'rivagan_decoder.onnx'), providers=['CUDAExecutionProvider'])

Then, you can run the code on the GPU.

image quality degradation

Dears, thanks for you great job first. When I try add watermask of image, the output image quality degradation. But when I use watermask of text, the output is good, but text version is not robut for crop operation. Some code like following:
"import time

加水印

import cv2
from imwatermark import WatermarkEncoder
tic = time.time()
bgr = cv2.imread('pic/ori_senwang.png')
wm = '@guofei9987威尼斯'
encoder = WatermarkEncoder()
encoder.set_watermark('bytes', wm.encode('utf-8'))
bgr_encoded = encoder.encode(bgr, 'dwtDctSvd') # dwtDct
print('take time:', time.time()-tic)
cv2.imwrite('output/test_wm.png', bgr_encoded)

解水印

import cv2
from imwatermark import WatermarkDecoder

bgr1 = cv2.imread('output/test_wm.png')
bgr1 = bgr1#[:1200, :800, ...]
decoder = WatermarkDecoder('bytes', 8*len(wm.encode('utf-8')))
watermark = decoder.decode(bgr1, 'dwtDctSvd')
print(watermark.decode('utf-8', 'replace'))"

Windows CLI

I've installed it on my windows machine works fine with script but I would like to use it as CLI but I see there is no exe provided,
Any help on how I could compile it myself from source ?
Thanks

Bug - dwtDct doesnt work for any image tried - The other two Methods work fine

I used your test code for reading/writing. I also left it on: dwtDct

No matter what test image i test, when i attempt to read it back i always get back garbled text.

It is only when i switch to the much slower dwtDctSvd or riv that the reading the wm works fine.

Seems its a bug.

Here is the code:

Write:

import cv2
from imwatermark import WatermarkEncoder
bgr = cv2.imread('E:/Desktop/white.png')
wm = '12345678'
encoder = WatermarkEncoder()
encoder.set_watermark('bytes', wm.encode('utf-8'))
bgr_encoded = encoder.encode(bgr, 'dwtDct')
cv2.imwrite('E:/Desktop/white-wm.png', bgr_encoded)

Read:
import cv2
from imwatermark import WatermarkDecoder
bgr = cv2.imread('E:/Desktop/white-wm.png')
decoder = WatermarkDecoder('bytes', 64)
watermark = decoder.decode(bgr, 'dwtDct')
print('Decoded Message is:' + watermark.decode('utf-8'))

The white.png file is here: https://upload.wikimedia.org/wikipedia/commons/thumb/7/70/Solid_white.svg/1024px-Solid_white.svg.png

When i read the decoded message is always blank

UnicodeDecodeError: invalid continuation byte, using dwtDct

Hi, currently testing on invisible watermarks, thanks for your work.
I met an error while running this code, modified some from given example:

import cv2
from imwatermark import WatermarkEncoder, WatermarkDecoder

if __name__ == "__main__":
    mode = "encode"  # [encode, decode]
    method = "dwtDct"  # [dwtDct, dwtDctSvd, rivaGan]
    wm = "test"

    if mode == "encode":
        bgr = cv2.imread("FaceShifter_765_867_frame00009_face000.png", -1)
        h, w, c = bgr.shape
        if h < 256 and w < 256:
            bgr = cv2.resize(bgr, (256, 256), interpolation=cv2.INTER_CUBIC)
        elif h < 256:
            bgr = cv2.resize(bgr, (w, 256), interpolation=cv2.INTER_CUBIC)
        elif w < 256:
            bgr = cv2.resize(bgr, (h, 256), interpolation=cv2.INTER_CUBIC)
        encoder = WatermarkEncoder()
        encoder.set_watermark("bytes", wm.encode("utf-8"))
        bgr_encoded = encoder.encode(bgr, method)
        cv2.imwrite("invisible_watermark_3_{}.png".format(method), bgr_encoded)
    else:  # decode
        bgr = cv2.imread("invisible_watermark_3_{}.png".format(method), -1)
        decoder = WatermarkDecoder("bytes", len(wm) * 8)
        watermark = decoder.decode(bgr, method)
        print(watermark)
        watermark_txt = watermark.decode("utf-8")
        with open("recon_watermark_3_{}.txt".format(method), "w") as f:
            f.write(watermark_txt + "\n")

And I get UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf4 in position 0: invalid continuation byte since the watermark after decoding shows b'\xf4\x7f\xfb\xff' while the encoded byte of test should be b'\x74\x65\x73\x74'.

Did I do something wrong? My original image size is (193, 193, 3), python version 3.8.18, cv2 version 4.9.0.80.

I also tried: b'\xf4\x7f\xfb\xff'.decode("utf-8", "replace") which gives '_\x7f__', not the valid watermark.

Many thanks for any help!

p.s. this issue is for using dwtDct, so please not recommend me to use other methods since it's not a solution.

CLI decode doesn't work if output image is JPG

I'm trying to use as CLI and python script to generate a wmrked JPG but watermark decode doesn't show anything:

C:\Users\me\AppData\Local\Programs\Python\Python310\Scripts>py invisible-watermark "F:\JPEG\_DSC5341.jpg" -v -a encode -t bytes -m dwtDct -w '1234' -o "F:\JPEG\_DSC5341-w.jpg"
watermark length: 48
encode time ms: 2819.3318843841553

C:\Users\me\AppData\Local\Programs\Python\Python310\Scripts>py invisible-watermark "F:\JPEG\_DSC5341-w.jpg" -v -a decode -t bytes -m dwtDct -l 48
decode time ms: 1944.9546337127686

It's like there is no watermark impressed in it, unless I use a PNG as output.
I posted the images I'm using for test purpouses.

raw img
test
wm img
test_wm

Example code not working

encoded the image, then decoding returned nothing, not "test" like expected.

edit: tried with a different png image:
Traceback (most recent call last):
File "/home/me/whisper/decode.py", line 8, in
print(watermark.decode('utf-8'))
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte

Onnx Providers Missing

In newer versions of Onnx the runtime providers need to be included, otherwise the onnx model inference will fail. Proposed solution here: #25.

Install with pip fails on python3.11

To reproduce create an empty venv.

ERROR: Cannot install invisible-watermark==0.1.0, invisible-watermark==0.1.1, invisible-watermark==0.1.2, invisible-watermark==0.1.3, invisible-watermark==0.1.4 and invisible-watermark==0.1.5 because these package versions have conflicting dependencies.

The conflict is caused by:
invisible-watermark 0.1.5 depends on onnxruntime
invisible-watermark 0.1.4 depends on onnxruntime
invisible-watermark 0.1.3 depends on onnxruntime
invisible-watermark 0.1.2 depends on onnxruntime
invisible-watermark 0.1.1 depends on torch==1.0.1.post2
invisible-watermark 0.1.0 depends on torch==1.0.1.post2

.

.

Publish source distribution to pypi

Hi, thanks for providing this library!

I was wondering if you would be able to publish the source distribution on pypi. I see that it is available in versions <= 0.1.5 (link), but not in the latest 0.2.0 version (link). This is preventing me from pulling the library into our internal repos, which requires scanning the source code.

Thank you

Enhancement: Determining if an image can hold the desired watermark

Using the following code block to create a sample image, encode it with a uuid, and then decode it results in erroneous restructuring of uuid that was encoded.

from imwatermark import WatermarkEncoder, WatermarkDecoder
import cv2
if __name__ == "__main__":
    large_image = np.ones((256, 256, 3), dtype=np.uint8)
    large_image *= 255

    encoder = WatermarkEncoder()
    original_uuid = 'urn:uuid:a9c072b1-c796-4a0c-8b81-25e4f2259c01'
    # Have also tried:
    #     original_uuid = 'a9c072b1-c796-4a0c-8b81-25e4f2259c01'
    #     original_uuid = 'a9c072b1c7964a0c8b8125e4f2259c01'
    encoder.set_watermark('uuid', original_uuid)
    # Have also tried:
    #     encoder.set_by_uuid(original_uuid)
    bgr_encoded = encoder.encode(large_image, 'dwtDct')
    cv2.imwrite('test.png', bgr_encoded)
    print(bgr_encoded.min(), bgr_encoded.max())  # results in: 251 255
    decoder = WatermarkDecoder('uuid')
    watermark = decoder.decode(bgr_encoded, 'dwtDct')
    print(watermark)  # results in: 00000000-0000-0000-0000-000000000000
    assert watermark == original_uuid.replace('urn:uuid:', '')  # results in: False

Have also tried dwtDctSvd

Environment:

  • Ubuntu 22.04
  • Python 3.10
  • invisible-watermark -- 0.2.0 (latest)

is non-persistence a known issue?

I kinda don't know what anyone wants to achieve with this, but you are aware that it is not invariant to repeated execution, are you? (at least the thing I tested "dwtDctSvd" .. the others did not work )
this means the watermark can be "cleared"

PIL support

Is it possible to support PIL as alternative to CV2?

Thank you.

Unable to decode the message

"""Watermark snippet. https://github.com/ShieldMnt/invisible-watermark"""

from imwatermark import WatermarkEncoder, WatermarkDecoder
from PIL import Image
import cv2
import numpy as np
watermark: str = "ritw"  # Do not use space bar
my_bytes: int = 8 * len(watermark)  # Need when do decoding.

def watermark_encode(in_image: Image) -> Image:
    """Encode the image with static watermark."""
    numpy_array = np.array(in_image)
    cv2_image = cv2.cvtColor(numpy_array, cv2.COLOR_RGB2BGR)

    encoder = WatermarkEncoder()
    encoder.set_watermark('bytes', watermark.encode('utf-8'))
    bgr_encoded = encoder.encode(cv2_image, 'dwtDct')
    # import cv2
    # cv2.imwrite('test_wm.png', bgr_encoded)
    result = Image.fromarray(bgr_encoded)
    return result

def watermark_decode(in_image: Image) -> str:
    """Decode the watermarked image."""
    numpy_array = np.array(in_image)
    cv2_image = cv2.cvtColor(numpy_array, cv2.COLOR_RGB2BGR)
    decoder = WatermarkDecoder('bytes', my_bytes)
    watermark = decoder.decode(cv2_image, 'dwtDct')
    # Dead this line
    import ipdb; ipdb.set_trace()
    return watermark.decode('utf-8')

watermark.decode('utf-8') will raises *** UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb3 in position 0: invalid start byte

Python 3.11.3
invisible-watermark==0.2.0

Potentially performance issues

When using an image larger than 1MB the performance degradates quickly. What we observe is that with an image of 1920 × 1080 the performance is great, but using an image of 9504 × 6336 inside a container with 20GB of RAM after ~40 minutes the flask repository we put on top of the library crashes because the container is OOM.
Is there a way to improve performance in this sense?

WatermarkDecoder returns 'test'

I watermarked the image using dwtDctSvd. When using the WatermarkDecoder on this image, the output is 'test.' I also tried saving the watermarked image in .jpg and .png formats, but the output remains the same.
I tried using watermark.decode('utf-8','replace'), but the result is same.
Additionally, I tested if the initial image can be watermarked using the code given here (#30 (comment)). This returns true for my image.

Is this expected for the WatermarkDecoder? If yes, what does this mean?

## ENCODING

import cv2
from imwatermark import WatermarkEncoder

bgr = cv2.imread('Image_2024.jpg')
wm = 'test'

encoder = WatermarkEncoder()
encoder.set_watermark('bytes', wm.encode('utf-8'))
bgr_encoded = encoder.encode(bgr, 'dwtDctSvd')

cv2.imwrite('test_wm.jpg', bgr_encoded)

## DECODING

import cv2
from imwatermark import WatermarkDecoder

bgr = cv2.imread('test_wm.jpg')

decoder = WatermarkDecoder('bytes', 32)
watermark = decoder.decode(bgr, 'dwtDctSvd')
print(watermark.decode('utf-8',))

import cv2
from imwatermark import WatermarkDecoder

bgr = cv2.imread('test_wm.png')

decoder = WatermarkDecoder('bytes', 32)
watermark = decoder.decode(bgr, 'dwtDctSvd')
print(watermark.decode('utf-8',))

watermark.decode('utf-8','replace')

Image file size decreases

Hi,
What I observed is the image file size before adding invisible watermark is 2.7 mb.
Image = 1816 × 1382. After adding watermark text oflength = 41.

        encoder = WatermarkEncoder()
        encoder.set_watermark('bytes', invisible_watermark_text.encode('utf-8'))
        bgr_encoded = encoder.encode(cv2_img_obj, 'dwtDctSvd')
        # print("Invisible watermark added to the image")

        # Convert back to OpenCV format
        _, encoded_img = cv2.imencode('.jpeg', bgr_encoded)

The file size reduces to 0.35 mb

any idea why and how can I retain the original file size?

rivagan error prevents dct decode on a non-cuda computer

(base) Douglass-MacBook-Pro:invisible-watermark-main doug$ ./invisible-watermark -v -a decode -t bytes -m dwtDct -l 32 ./"00007-3643514179.png"
Traceback (most recent call last):
File "/Users/doug/Downloads/invisible-watermark-main/./invisible-watermark", line 22, in
from imwatermark import WatermarkEncoder, WatermarkDecoder
File "/Users/doug/Downloads/invisible-watermark-main/imwatermark/init.py", line 1, in
from .watermark import WatermarkEncoder, WatermarkDecoder
File "/Users/doug/Downloads/invisible-watermark-main/imwatermark/watermark.py", line 9, in
from .rivaGan import RivaWatermark
File "/Users/doug/Downloads/invisible-watermark-main/imwatermark/rivaGan.py", line 2, in
import torch
File "/Users/doug/.pyenv/versions/3.10.0a7/lib/python3.10/site-packages/torch/init.py", line 676, in
from .storage import _StorageBase, TypedStorage, _LegacyStorage, UntypedStorage
File "/Users/doug/.pyenv/versions/3.10.0a7/lib/python3.10/site-packages/torch/storage.py", line 856, in
class _LegacyStorage(TypedStorage, metaclass=_LegacyStorageMeta):
TypeError: 'torch._C._TensorMeta' object is not iterable

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.