图像中的隐形水印
为了版权目的,如何在图像中插入不可见的水印?我在寻找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压缩数据,并以提供的文件名不压缩地保存。
我验证了旧代码仍然可以运行,因此这是一个包含隐写数据的示例图像:
我们会注意到几乎看不到增加的噪音。