【OpenCV 例程 300篇】219. 添加数字水印(盲水印)

OpenCV 例程200篇 总目录


【youcans 的 OpenCV 例程 300篇】219. 添加数字水印(盲水印)

8.2 添加数字盲水印

数字水印,是指将特征信息嵌入音频、图像或是视频等数字信号中。

数字水印分为明水印和盲水印(blind watermark)。明水印包含的信息在观看图像或视频时可以看到。盲水印是以数字数据的方式嵌入图像中,在一般条件下是看不到的,需要特殊处理后才能提取到水印信息。盲水印也称为隐藏式水印,可以实现信息隐藏、版权认证、身份认证、数字签名等功能。

最低有效位(Least significant bit)盲水印,是最简单方便的盲水印实现方法。该方法的原理是将数字水印信息保存为二值图像,嵌入到原始图像的最低位,即将原始图像的最低有效位替换为水印图像。

以 8 位灰度图像为例,原始图像中像素点 P 的灰度值由 8 位二进制数 ( p 7 , p 6 , . . . , p 1 , p 0 ) (p_7, p_6,...,p_1,p_0) (p7,p6,...,p1,p0) 表示,二值水印图像中像素点的像素值由 1 位二进制数 b 0 b_0 b0 表示。用水印图像的像素值 b 0 b_0 b0 替换原始图像的最低有效位 p 0 p_0 p0,就得到嵌入水印的 8 位二进制数 ( p 7 , p 6 , . . . , p 1 , b 0 ) (p_7, p_6,...,p_1,b_0) (p7,p6,...,p1,b0)

提取盲水印的过程与嵌入水印相反,从嵌入水印的原始图像 8 位二进制数 ( p 7 , p 6 , . . . , p 1 , b 0 ) (p_7, p_6,...,p_1,b_0) (p7,p6,...,p1,b0) 中,分离最低有效位 b 0 b_0 b0 生成水印图像。

提取盲水印的过程,则是对于嵌入水印的原始图像,将 8 位二进制数 ( p 7 , p 6 , . . . , p 1 , b 0 ) (p_7, p_6,...,p_1,b_0) (p7,p6,...,p1,b0) 的最低有效位置零。


例程 A4.11:在灰度图像添加数字盲水印

    # A4.10 在灰度图像嵌入数字盲水印
    img = cv.imread("../images/imgLena.tif", 0)  # 加载原始图片,单通道
    watermark = cv.imread("../images/logoCV.png", 0)  # # 加载水印图片,单通道
    markResize = cv.resize(watermark, img.shape[:2])  # 调整图片尺寸与 img 大小相同
    _, binary = cv.threshold(markResize, 175, 1, cv.THRESH_BINARY)  # 0/1 二值图像

    # 对原始图像嵌入水印
    # img (g7,g6,...g1,0) AND 254(11111110) -> imgH7: (g7,g6,...g1,0)
    imgH7 = cv.bitwise_and(img, 254)  # 按位与运算,图像最低位 LSB=0
    # imgH7: (g7,g6,...g1,0) OR b -> imgMark: (g7,g6,...g1,b)
    imgMark = cv.bitwise_or(imgH7, binary)  # (g7,g6,...g1,b)

    # 从嵌入水印图像中提取水印
    # extract = np.mod(imgMark, 2)  # 模运算,取图像的最低位 LSB
    extract = cv.bitwise_and(imgMark, 1)  # 按位与运算,取图像的最低位 LSB

    plt.figure(figsize=(9, 6))
    plt.subplot(221), plt.title("original gray"), plt.axis('off')
    plt.imshow(img, cmap='gray')
    plt.subplot(222), plt.title("watermark"), plt.axis('off')
    plt.imshow(binary, cmap='gray')
    plt.subplot(223), plt.title("embedding watermark"), plt.axis('off')
    plt.imshow(imgMark, cmap='gray')
    plt.subplot(224), plt.title("extracted watermark"), plt.axis('off')
    plt.imshow(extract, cmap='gray')
    plt.tight_layout()
    plt.show()

在这里插入图片描述


例程 A4.12:在彩色图像各通道嵌入不同内容的数字盲水印

把彩色图像的各个通道分离处理,可以嵌入相同内容的数字水印,也可以嵌入不同内容的数字水印。

    # A4.12 在彩色图像各通道嵌入不同内容的数字盲水印
    img = cv.imread("../images/imgLena.tif", 1)  # 加载原始图片,单通道

    # 加载或生成水印信息
    watermark = cv.imread("../images/logoCV.png", 0)  # # 加载水印图片,单通道
    markResize = cv.resize(watermark, img.shape[:2])  # 调整图片尺寸与 img 大小相同
    _, binary = cv.threshold(markResize, 175, 1, cv.THRESH_BINARY)  # 0/1 二值图像

    mark1 = np.ones(img.shape[:2], np.uint8)
    cv.putText(mark1, str(np.datetime64('today')), (50, 100), cv.FONT_HERSHEY_SIMPLEX, 2, 0, 2)
    cv.putText(mark1, str(np.datetime64('now')), (50, 150), cv.FONT_HERSHEY_DUPLEX, 1, 0)

    mark2 = np.ones(img.shape[:2], np.uint8)
    cv.putText(mark2, "200 examples for OpenCV", (50, 300), cv.FONT_HERSHEY_SIMPLEX, 2, 0, 2)
    cv.putText(mark2, "Copyright@youcans, 2022", (50, 350), cv.FONT_HERSHEY_DUPLEX, 1, 0)

    # 对原始图像嵌入水印
    # img: (g7,g6,...g1,0) -> imgH7: (g7,g6,...g1,0)
    imgH7 = (img >> 1) << 1  # 右移->左移,图像最低位 LSB=0
    # imgH7: (g7,g6,...g1,0) OR b -> imgMark: (g7,g6,...g1,b)
    # 对各通道分别插入数字水印 binary,mark1,mark2
    b = cv.bitwise_or(imgH7[:, :, 0], binary)  # (g7,g6,...g1,b)
    g = cv.bitwise_or(imgH7[:, :, 1], mark1)  # (g7,g6,...g1,m1)
    r = cv.bitwise_or(imgH7[:, :, 2], mark2)  # (g7,g6,...g1,m2)
    imgMark = cv.merge([b, g, r])

    # # 从嵌入水印图像中提取水印
    b, g, r = cv.split(imgMark)  # 拆分为 BGR 独立通道
    bMark = cv.bitwise_and(b, 1)  # 按位与运算,取 B 通道的最低位 LSB
    gMark = cv.bitwise_and(g, 1)  # 按位与运算,取 G 通道的最低位 LSB
    rMark = cv.bitwise_and(r, 1)  # 按位与运算,取 R 通道的最低位 LSB

    plt.figure(figsize=(9, 6))
    plt.subplot(231), plt.title("original gray"), plt.axis('off')
    plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
    plt.subplot(232), plt.title("watermark"), plt.axis('off')
    plt.imshow(binary, cmap='gray')
    plt.subplot(233), plt.title("embedding watermark"), plt.axis('off')
    plt.imshow(cv.cvtColor(imgMark, cv.COLOR_BGR2RGB))
    plt.subplot(234), plt.title("watermark ch-B"), plt.axis('off')
    plt.imshow(bMark, cmap='gray')
    plt.subplot(235), plt.title("watermark ch-G"), plt.axis('off')
    plt.imshow(gMark, cmap='gray')
    plt.subplot(236), plt.title("watermark ch-R"), plt.axis('off')
    plt.imshow(mark2, cmap='gray')
    plt.show()

在这里插入图片描述


【本节完】

版权声明:
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/125506913)
Copyright 2022 youcans, XUPT
Crated:2022-7-5
欢迎关注 『youcans 的 OpenCV 例程 200 篇』 系列,持续更新中

218. 多行倾斜文字水印
219. 添加数字盲水印

  • 8
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
在Spring Boot中使用OpenCV实现添加水印和获取水印,可以参考以下步骤: 1. 添加OpenCV依赖 在pom.xml文件中添加OpenCV依赖,例如: ```xml <dependency> <groupId>org.openpnp</groupId> <artifactId>opencv</artifactId> <version>4.5.1-1</version> </dependency> ``` 2. 实现添加水印 通过OpenCV实现添加水印的步骤如下: - 读取原图像和水印图像; - 将水印图像转换为灰度图像; - 将水印图像缩小到原图像的1/4大小; - 将水印图像嵌入到原图像中; - 保存嵌入水印后的图像。 示例代码如下: ```java import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; public class Watermark { public static void addWatermark(String imagePath, String watermarkPath, String outputPath) { // 加载OpenCV库 System.loadLibrary(Core.NATIVE_LIBRARY_NAME); // 读取原图像和水印图像 Mat image = Imgcodecs.imread(imagePath); Mat watermark = Imgcodecs.imread(watermarkPath, Imgcodecs.IMREAD_GRAYSCALE); // 将水印图像缩小到原图像的1/4大小 Imgproc.resize(watermark, watermark, image.size(), 0.25, 0.25, Imgproc.INTER_AREA); // 将水印图像嵌入到原图像中 Core.addWeighted(image, 1.0, watermark, 0.5, 0, image); // 保存嵌入水印后的图像 Imgcodecs.imwrite(outputPath, image); } } ``` 3. 实现获取水印 通过OpenCV实现获取水印的步骤如下: - 读取带水印的图像; - 将图像转换为灰度图像; - 提取水印信息; - 将提取的水印信息输出。 示例代码如下: ```java import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; public class Watermark { public static void extractWatermark(String imagePath) { // 加载OpenCV库 System.loadLibrary(Core.NATIVE_LIBRARY_NAME); // 读取带水印的图像 Mat image = Imgcodecs.imread(imagePath); // 将图像转换为灰度图像 Imgproc.cvtColor(image, image, Imgproc.COLOR_BGR2GRAY); // 提取水印信息 // TODO: 实现提取水印信息的算法 // 输出提取的水印信息 // TODO: 输出提取的水印信息 } } ``` 需要注意的是,提取水印需要使用特定的算法,这里只是示例代码,具体实现需要根据实际情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

youcans_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值