图像中的隐形水印

时间:2020-03-05 18:47:42  来源:igfitidea点击:

为了版权目的,如何在图像中插入不可见的水印?我在寻找python库。

我们使用什么算法?性能和效率又如何呢?

解决方案

回答

那Exif呢?它可能不像我们所想的那样安全,但是大多数用户甚至都不知道它的存在,如果我们能够轻松读取水印信息,那么那些关心的人仍然可以这样做。

回答

我认为没有现成的库可以做到这一点。如果我们想实现自己的,我肯定会选择Python Imaging Library(PIL)。

这是Python Cookbook食谱,使用PIL向图像添加可见水印。如果足够满足需求,则可以使用它添加具有足够透明度的水印,只有在我们知道要查找的内容时才可见。

回答

我们可能需要研究隐写术;就是将数据隐藏在图像内部。如果我们转换为有损格式,甚至裁剪掉图像的某些部分,有些表格也不会丢失。

回答

我本来打算发布与Ugh类似的答案。我建议以难以检测和破坏的方式,将描述图像来源的小TXT文件(如果适用的话,可能还附上一份版权声明)放入图像中。

回答

我不确定牢不可破的重要性,但是一个简单的解决方案可能只是将文本文件添加到图像的末尾。诸如"此图像属于..."之类的东西。

如果在查看器/浏览器中打开图像,则它看起来像普通的jpeg,但是如果在文本编辑器中打开图像,则最后一行是可读的。

使用相同的方法可以将实际文件包含在图像中。 (在图像内隐藏文件)我发现它有点命中注定,但是7压缩文件似乎可以工作。我们可以在图像中隐藏各种copywrite好东西。

再次强调,这并非凭空想像,这是坚不可摧的,但肉眼却是完全看不见的。

回答

某些图像格式具有标头,我们也可以在其中存储任意信息。
例如,PNG规范有一个块,我们可以在其中存储文本数据。这与上面的答案类似,但是没有向图像数据本身添加随机数据。

回答

我正在寻找"牢不可破"的水印,因此存储在exif或者图像元数据中的数据已用完。

在等待回复的同时,我在网上发现了一些有趣的内容:
http://www.cosy.sbg.ac.at/~pmeerw/Watermarking/

有一篇硕士论文对算法及其特性(它们做什么以及它们有多坚不可摧)进行了详尽的介绍。我没有时间深入阅读它,但是这东西看起来很严肃。有些算法以某种方式支持JPEG压缩,裁剪,伽玛校正或者缩小。它是C,但是我可以将其移植到Python或者使用Python中的C库。

但是,这是从2001年开始的,我想在该领域已经有7年的历史了:(是否有人拥有一些相似且更新的资料?

回答

我使用以下代码。它需要PIL:

def reduceOpacity(im, opacity):
    """Returns an image with reduced opacity."""
    assert opacity >= 0 and opacity <= 1
    if im.mode != 'RGBA':
        im = im.convert('RGBA')
    else:
        im = im.copy()
    alpha = im.split()[3]
    alpha = ImageEnhance.Brightness(alpha).enhance(opacity)
    im.putalpha(alpha)
    return im

def watermark(im, mark, position, opacity=1):
    """Adds a watermark to an image."""
    if opacity < 1:
        mark = reduceOpacity(mark, opacity)
    if im.mode != 'RGBA':
        im = im.convert('RGBA')
    # create a transparent layer the size of the image and draw the
    # watermark in that layer.
    layer = Image.new('RGBA', im.size, (0,0,0,0))
    if position == 'tile':
        for y in range(0, im.size[1], mark.size[1]):
            for x in range(0, im.size[0], mark.size[0]):
                layer.paste(mark, (x, y))
    elif position == 'scale':
        # scale, but preserve the aspect ratio
        ratio = min(float(im.size[0]) / mark.size[0], float(im.size[1]) / mark.size[1])
        w = int(mark.size[0] * ratio)
        h = int(mark.size[1] * ratio)
        mark = mark.resize((w, h))
        layer.paste(mark, ((im.size[0] - w) / 2, (im.size[1] - h) / 2))
    else:
        layer.paste(mark, position)
    # composite the watermark with the layer
    return Image.composite(layer, im, layer)

img = Image.open('/path/to/image/to/be/watermarked.jpg')

mark1 = Image.open('/path/to/watermark1.png')
mark2 = Image.open('/path/to/watermark2.png')

img = watermark(img, mark1, (img.size[0]-mark1.size[0]-5, img.size[1]-mark1.size[1]-5), 0.5)
img = watermark(img, mark2, 'scale', 0.01)

水印太微弱,看不到。只有纯色图像才能真正显示它。我可以使用它来创建不显示水印的图像,但是如果我使用原始图像进行逐位减法,则可以证明我的水印在那里。

如果要查看其工作原理,请访问TylerGriffinPhotography.com。该站点上的每个图像都被加水印两次:一次是水印在右下角的不透明度为50%(距边缘5像素),一次是在整个图像中以1%的不透明度(使用"比例"),该比例将水印缩放为整个图片)。我们能找出第二个低不透明度水印形状是什么吗?

回答

好吧,隐形水印并不是那么容易。看看digimarc,他们从中赚了多少钱。没有免费的C / Python代码,一个孤独的天才写了一个留给他免费使用的代码。我已经实现了自己的算法,该工具的名称为SignMyImage。谷歌如果有兴趣... F>

回答

watermarkingworld.org上有更新的(2005)数字水印常见问题解答。

回答

如果我们正在谈论隐写术,那么这是我曾经为朋友做过的一个不太老的模块(Python 2.x代码):

代码

from __future__ import division

import math, os, array, random
import itertools as it
import Image as I
import sys

def encode(txtfn, imgfn):
    with open(txtfn, "rb") as ifp:
        txtdata= ifp.read()
    txtdata= txtdata.encode('zip')

    img= I.open(imgfn).convert("RGB")
    pixelcount= img.size[0]*img.size[1]
##  sys.stderr.write("image %dx%d\n" % img.size)

    factor= len(txtdata) / pixelcount
    width= int(math.ceil(img.size[0]*factor**.5))
    height= int(math.ceil(img.size[1]*factor**.5))

    pixelcount= width * height
    if pixelcount < len(txtdata): # just a sanity check
        sys.stderr.write("phase 2, %d bytes in %d pixels?\n" % (len(txtdata), pixelcount))
        sys.exit(1)
##  sys.stderr.write("%d bytes in %d pixels (%dx%d)\n" % (len(txtdata), pixelcount, width, height))
    img= img.resize( (width, height), I.ANTIALIAS)

    txtarr= array.array('B')
    txtarr.fromstring(txtdata)
    txtarr.extend(random.randrange(256) for x in xrange(len(txtdata) - pixelcount))

    newimg= img.copy()
    newimg.putdata([
        (
            r & 0xf8 |(c & 0xe0)>>5,
            g & 0xfc |(c & 0x18)>>3,
            b & 0xf8 |(c & 0x07),
        )
        for (r, g, b), c in it.izip(img.getdata(), txtarr)])
    newimg.save(os.path.splitext(imgfn)[0]+'.png', optimize=1, compression=9)

def decode(imgfn, txtfn):
    img= I.open(imgfn)
    with open(txtfn, 'wb') as ofp:
        arrdata= array.array('B',
            ((r & 0x7) << 5 | (g & 0x3) << 3 | (b & 0x7)
            for r, g, b in img.getdata())).tostring()
        findata= arrdata.decode('zip')
        ofp.write(findata)

if __name__ == "__main__":
    if sys.argv[1] == 'e':
        encode(sys.argv[2], sys.argv[3])
    elif sys.argv[1] == 'd':
        decode(sys.argv[2], sys.argv[3])

算法

它使用以下各项为每个图像像素存储一个字节的数据:蓝色带的3个最低有效位,绿色带的2 LSB和红色带的3 LSB。

编码功能:使用zlib压缩输入文本文件,并调整输入图像的大小(保持比例),以确保至少有与压缩字节一样多的像素。保存了与输入图像同名的PNG图像(因此,如果我们按原样保留代码,请不要使用" .png"文件名作为输入),其中包含隐写数据。

解码功能:从输入图像中提取先前存储的zlib压缩数据,并以提供的文件名不压缩地保存。

我验证了旧代码仍然可以运行,因此这是一个包含隐写数据的示例图像:

我们会注意到几乎看不到增加的噪音。