ShieldMnt / invisible-watermark

python library for invisible image watermark (blind image watermark)
MIT License
1.61k stars 150 forks source link

Unable to decode the message #23

Open elcolie opened 1 year ago

elcolie commented 1 year ago

"""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

Void-JackLee commented 1 year ago
def decode(img_name, length):
    bgr = cv2.imread(img_name)
    decoder = WatermarkDecoder('bytes', length)
    watermark = decoder.decode(bgr, METHOD)
    print(watermark.decode('utf-8'))

Similar problem occurs in particular image UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte.

bt0r commented 1 year ago

Hi guys, I faced the same issue, it seems some pictures are affected and cannot be watermarked. I found a workaround by editing the picture with a noise filter or other filter that add/change pixel colors.

Some examples

Base image cannot be used to add watermark, rather than the output ones Its the only solution i found to make it work, i know its not the best one because it changes the picture quality/render. Feel free to suggest new ideas :)

Using gradient filtering (edited manually on pixelmator/photoshop)

Base image

6

Output

6_1

Using noise filtering

Base image

6

Output

6
    im = Image.open(image_path)
    final_image = Image.new('RGBA', im.size)
    # Generate multicolor noise
    pixel_data = np.random.randint(
        low=0,
        high=256,
        size=(im.size[1], im.size[0], 3),
        dtype=np.uint8
    )
    new_noise = Image.fromarray(pixel_data)
    new_noise.putalpha(230) # change this value to add/remove transparency
    new_noise.convert('RGBA')
    final_image.paste(new_noise)
    final_image.paste(im, (0, 0), new_noise)

    final_image.save('/your/out/path')

Maybe linked to #16 #10 #2

rgill02 commented 1 year ago

Instead of using method 'dwtDct' try using method 'dwtDctSvd' as it seems to be more reliable (at the cost of performance).

lifeofstudy commented 6 months ago

"""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

It seems to be an inherent error in the method dwtDct itself. There is no problem using dwtDctSvd.