Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement: Determining if an image can hold the desired watermark #30

Open
mexicantexan opened this issue Jan 29, 2024 · 3 comments
Open

Comments

@mexicantexan
Copy link

mexicantexan commented Jan 29, 2024

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)
@mexicantexan
Copy link
Author

mexicantexan commented Jan 29, 2024

Have also tried the bytes method which results in the same erroneous output:

new_uuid = uuid.UUID('urn:uuid:a9c072b1-c796-4a0c-8b81-25e4f2259c01').bytes
print(new_uuid.__repr__())  # b'\xa9\xc0r\xb1\xc7\x96J\x0c\x8b\x81%\xe4\xf2%\x9c\x01'
encoder = WatermarkEncoder()
encoder.set_by_bytes(new_uuid)
bgr_encoded = encoder.encode(large_image, 'dwtDctSvd')
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, 'dwtDctSvd')
print(watermark)  # results in: 00000000-0000-0000-0000-000000000000

Have also tried the dwtDct as well

@mexicantexan
Copy link
Author

mexicantexan commented Jan 30, 2024

Is there a minimum "complexity"/"chaos" (differences in pixel values) that needs to take place in the image? If that is the case, maybe there is a way to calculate this "complexity"/"chaos"?

@mexicantexan
Copy link
Author

mexicantexan commented Feb 5, 2024

Could add a helper function like:

def can_fit_watermark(watermark_str, image_cv2, num_coefficients=None, threshold=0.1) -> bool:
    """
    Estimates if an image can hold a given watermark.
    
    :param watermark_str: The watermark to embed, as a string.
    :param image_cv2: The image into which the watermark is to be embedded, as a cv2.Mat object.
    :param num_coefficients: Optional. The number of DWT-DCT coefficients to consider for watermarking.
                             If None, uses all coefficients.
    :param threshold: The threshold for pass/fail criteria based on the modifications' visibility.
                      Represents the maximum average change allowed per coefficient.
    :return: Boolean indicating whether the image can hold the watermark.
    """
    watermark_bits = ''.join(format(ord(char), '08b') for char in watermark_str)
    watermark_size = len(watermark_bits)
    
    # Convert image to grayscale for simplicity
    yuv = cv2.cvtColor(image_cv2, cv2.COLOR_BGR2YUV)
    gray_u_image = yuv[:,:,1]

    cA, (cH, cV, cD) = pywt.dwt2(gray_u_image, 'haar')
    dct_coefficients = np.fft.fft2(cA).flatten()
    num_coefficients = num_coefficients if num_coefficients else dct_coefficients.size
    modifiable_coefficients = min(num_coefficients, dct_coefficients.size)
    estimated_capacity = modifiable_coefficients * threshold
    
    # Check if the watermark fits within the estimated capacity
    return watermark_size <= estimated_capacity

@mexicantexan mexicantexan changed the title Simple image doesn't encode/decode Suggested Improvement: Determining if an image can hold the desired watermark Feb 20, 2024
@mexicantexan mexicantexan changed the title Suggested Improvement: Determining if an image can hold the desired watermark Enhancement: Determining if an image can hold the desired watermark Feb 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant