第3章:图像运算

第3章:图像运算

  • one. 图像加法运算:
    • 1. 加号运算符"+":
    • 2. cv2.add()函数:
  • two. 图像加权和:
  • three. 按位逻辑运算:
    • 1. 按位与运算:
    • 2. 按位或运算:
    • 3.按位非运算:
    • 4. 按位异或运算:
  • four. 掩膜:
  • five. 图像与数值运算:
  • six. 位平面分解:
  • seven. 图像加密和解密:
  • eight. 数字水印:
    • 1. 原理:
    • 2.实现方法:

图像的 加法运算位运算 都是比较基础的运算。但是很多复杂的图像处理功能正是借助这些基础的运算来完成的。例如:位平面分解、图像异或加密、数字水印等。

one. 图像加法运算:

在图像处理过程中,经常需要对图像进行加法运算。可以通过加号运算符"+"对图像进行加法运算,也可以通过cv2.add()函数对图像进行加法运算。

  • 加号运算符"+"
  • cv2.add()

通常情况下,在灰度图像中,像素用8个比特位(一个字节)来表示,像素值的范围是[0, 255]。两个像素值进行加法运算时,求得的和很可能超过255。上述两种不同的加法运算方式,对超过255的数值的处理方式是不一样的。

1. 加号运算符"+":

使用加号运算符"+"对图像a(像素值为a)和图像b(像素值为b)进行求和运算,遵循以下规则:

a+b={a+b,a+b≤255mod(a+b,256),a+b>255a+b = \begin{cases} a +b, \quad a+b≤255 \\ mod(a+b, 256), \quad a+b >255 \end{cases}a+b={a+b,a+b255mod(a+b,256),a+b255

式中mod():取模运算mod(a + b, 256)表示计算"a+b"的和除以256取余数。

根据以上规则,两个像素在进行加法运算时:

  • 如果两个图像对应像素值的和小于或等于255,则直接相加得到运算结果。例如:28和36相加得到64
  • 如果两个图像对应像素值的和大于255,则将运算结果对256取模。例如:255+58 = 313,则计算得到的结果是(255+58) % 256 = 57。

例如: 使用随机数数组模拟灰度图像,观察使用"+"对像素值求和的结果。

注意:通过将数组的类型定义为dtype = np.uint8,可以保证数组值的范围在[0, 255]之间

import numpy as npimg1 = np.random.randint(0, 256, size=[3, 3], dtype=np.uint8)
img2 = np.random.randint(0, 256, size=[3, 3], dtype=np.uint8)print('img1=\n', img1)
print('img2=\n', img2)
print('img1+img2=\n', img1+img2)

结果:

img1=[[241  85  79][ 62  29 113][ 33 129 150]]
img2=[[168  93 112][ 32 246 228][229  89 107]]
img1+img2=[[153 178 191][ 94  19  85][  6 218   1]]

注意:本例题中加法进行取模,是由数组类型dtype=np.uint8进行的。

2. cv2.add()函数:

函数cv2.add()可以用来计算图像像素值相加的和,语法格式:

  • result = cv2.add(a, b)

使用cv2.add()对像素值a, b进行求和运算时,遵循以下规则:a+b={a+ba+b≤255255a+b>255a + b = \begin{cases} a + b \quad a + b≤255 \\ 255 \quad a+b>255 \end{cases}a+b={a+ba+b255255a+b255

cv2.add()的参数有一下3种形式:

  • resutl = cv2.add(图像1, 图像2):两个参数都是图像,此时参与运算的图像大小和类型必须保持一致
  • result = cv2.add(数值,图像):第一个参数是数值,第二个参数是图像,此时将超过图像饱和值得数值处理为最大值。
  • result = cv2.add(图像,数值):第一个参数是图像,第二个参数是数值,此时将超过图像饱和值得数值处理为最大值。

例题: 分别使用加号运算符和函数cv2.add()计算两幅灰度图像的像素值之和。

import cv2
a = cv2.imread('../lena.bmp', 0)
b = a
result1 = a + b
resutl2 = cv2.add(a, b)
cv2.imshow('original', a)
cv2.imshow('result1', result1)
cv2.imshow('result2', resutl2)
cv2.waitKey()
cv2.destroyAllWindows()

在这里插入图片描述

从处理结果可以看出:

  • 使用加号运算符:会将和大于255的只进行取模运算,取模后大于255的这部分值变得更小了,导致本该更亮的点变得更暗了。
  • 使用函数cv2.add():将和大于255的值处理为饱和值255.图像像素值增大,图像整体变亮。

two. 图像加权和:

所谓图像加权和,就是在计算两幅图像的像素值之和时,将每幅图像的权重考虑进来,可以用公式表示为:dst=saturate(src1×α+src2×β+γ)dst = saturate(src1×\alpha + src2×\beta + \gamma)dst=saturate(src1×α+src2×β+γ)

式中,stautrate()表示取饱和值。图像进行加权和计算时,要求src1和src2必须大小、类型相同,但是具体是什么类型和通道没有特殊限制。他们可以是任意的数据类型,也可以有任意数量的通道。(灰度图像或者彩色图像)只要二者相同即可。

OpenCV中使用函数cv2.addWeighted() ,实现图像的加权和运算(混合、融合)。

语法格式:

  • dst = cv2.addWeighted(src1, alpha, src2, beta, gamma)

    其中,参数alpha和beta是src1和src2所对应的系数,它们的和可以等于1,也可以不等于1.该函数实现的功能是dat = src1 x alpha + src2 x beta + gamma。需要注意,式中参数gamma的可以是0,但是该参数是必选参数,不能省略。上式可以理解为 “result = 图像1 x 系数1 + 图像2 x 系数2 + 亮度调节量”

例1: 使用数组演示函数cv2.addWeighted()的使用。

import cv2
a = cv2.imread('../lena.bmp')
b = cv2.imread('../boat.512.tiff')
result = cv2.addWeighted(a, 0.6, b, 0.4, 0)
cv2.imshow('lena', a)
cv2.imshow('boat', b)
cv2.imshow('result', result)
cv2.waitKey()
cv2.destroyAllWindows()

在这里插入图片描述

three. 按位逻辑运算:

逻辑运算是一种非常重要的运算方式,图像处理过程中经常要按照位进行逻辑运算,下面介绍OpenCV中按位进行逻辑运算,简称位运算。

OpenCV中常见的位运算函数:

在这里插入图片描述

1. 按位与运算:

在与运算中,当参与与运算的两个逻辑值都是真时,结果才为真。其逻辑关系可以类比下图串联电路,只有两个开关都闭合时才会亮。

在这里插入图片描述

在这里插入图片描述

在OpenCV中,可以使用cv2.bitwise_and()函数来实现按位与操作,其语法格式:

  • dst = cv2.bitwise_and(src1, src2[, mask])

式中:

  • dst:表示与输入值具有同样大小的array输出值
  • src1:表示第一个array或scalar类型的输入值。
  • src2:表示第二个array或scalar类型的输入值。
  • mask:表示可选操作掩码,8位单通道array。

注意: 按位与操作有如下特点:

  • 将任何数值N与数值0进行按位与操作,得到的都是数值0
  • 将任何数值N(这里仅考虑8位值)与数值255(8位2进制是1111111)进行按位与操作,都会得到数值N本身。

在这里插入图片描述

例1: 构造一个淹没图像,使用按位与运算保留图像中被掩膜指定的部分。

import cv2
import numpy as np
a = cv2.imread('../lena.bmp', 0)
b = np.zeros(a.shape, dtype=np.uint8)
b[100: 400, 200: 400] = 255
b[100: 500, 100: 200] = 255c = cv2.bitwise_and(a, b)
cv2.imshow('a', a)
cv2.imshow('b', b)
cv2.imshow('c', c)
cv2.waitKey()
cv2.destroyAllWindows()

在这里插入图片描述

注意:除了会对灰度图像进行掩膜操作,还经常需要针对BGR模式的彩色图像使用掩膜提取指定部分。由于按位与操作要求参与运算的数据有相同的通道,所以无法直接将彩色图像与单通道的掩膜图像进行按位与操作。一般情况下,可以通过将掩膜图像转换为BGR模式的彩色图像,让彩色图像与掩膜图像进行按位与操作,实现掩膜运算

import cv2
import numpy as np
a = cv2.imread('../lena512color.tiff', 1)
b = np.zeros(a.shape, dtype=np.uint8)
b[100: 400, 200: 400] = 255
b[100: 500, 100: 200] = 255c = cv2.bitwise_and(a, b)
cv2.imshow('a', a)
cv2.imshow('b', b)
cv2.imshow('c', c)
cv2.waitKey()
cv2.destroyAllWindows()

在这里插入图片描述

2. 按位或运算:

或运算的规则是,当参与运算的两个逻辑值中有一个为真时,结果就为真。如下图并联电路:

在这里插入图片描述

在这里插入图片描述

在OpenCV中,可以使用cv2.bitwise_or()函数来实现按位或运算,其语法格式为:

  • dst = cv2.bitwise_or(src1, src2, [, mask])

式中:

  • dst:表示与输入值具有同样大小的array输出值
  • src1:表示第一个array或scalar类型的输入值。
  • src2:表示第二个array或scalar类型的输入值。
  • mask:表示可选操作掩码,8位单通道array。

在这里插入图片描述

3.按位非运算:

非运算是取反操作:

  • 当运算数为真时,结果为假;
  • 当运算数为假时,结果为真

在这里插入图片描述

按位非运算是指将数值转换成2进制值后,在对应的位置上进行非运算。

在OpenCV中,可以使用函数cv2.bitwise_not()来实现按位取反操作,其语法格式为:

  • dst = cv2.bitwise_not(src, [mask])

式中:

  • dst:表示与输入值具有同样大小的array输出值
  • src1:表示第一个array或scalar类型的输入值。
  • mask:表示可选操作掩码,8位单通道array。

在这里插入图片描述

4. 按位异或运算:

异或运算也叫半加运算,其运算法则与不带二进制位的加法类似,其英文为"exclusive OR",因此函数通常表示为xor

在这里插入图片描述

按位异或运算是指将数值转换成2进制值后,在对应的位置上进行异或运算。

在这里插入图片描述

在OpenCV中,可以使用函数cv2.bitwise_xor()来实现按位取反操作,其语法格式为:

  • dst = cv2.bitwise_xor(src1, src2, [mask])

式中:

  • dst:表示与输入值具有同样大小的array输出值
  • src1:表示第一个array或scalar类型的输入值。
  • src2:表示第二个array或scalar类型的输入值。
  • mask:表示可选操作掩码,8位单通道array。

four. 掩膜:

在OpenCV中很多函数都会指定一个掩膜,也成掩码,例如:

result = cv2.add(参数1, 参数2, 掩膜)

当使用掩膜参数时,操作只会在掩膜值为非空的像素点上执行,将其他的像素点置为0.

例1:

image1=∣3333333333333333333333333∣image2=∣5555555555555555555555555∣mask=∣0000000000000000001100011∣image1 = \begin{vmatrix} 3 & 3 & 3 & 3 & 3 \\ 3 & 3 & 3 & 3 & 3 \\3 & 3 & 3 & 3 & 3 \\3 & 3 & 3 & 3 & 3 \\3 & 3 & 3 & 3 & 3 \end{vmatrix} \quad image2 = \begin{vmatrix} 5 & 5 & 5 & 5 & 5 \\ 5 & 5 & 5 & 5 & 5 \\5 & 5 & 5 & 5 & 5 \\5 & 5 & 5 & 5 & 5 \\5 & 5 & 5 & 5 & 5 \end{vmatrix} \quad mask= \begin{vmatrix} 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 \\0 & 0 & 0 & 0 & 0 \\0 & 0 & 0 & 1 & 1 \\0 & 0 & 0 & 1 & 1 \end{vmatrix}image1=3333333333333333333333333image2=5555555555555555555555555mask=0000000000000000001100011

经过img3 = cv2.add(img1, img2, mask=mask) 运算后得image3:

img3=∣0000000000000000008800088∣img3= \begin{vmatrix} 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 \\0 & 0 & 0 & 0 & 0 \\0 & 0 & 0 & 8 & 8 \\0 & 0 & 0 & 8 & 8 \end{vmatrix}img3=0000000000000000008800088

在计算时,img3计算的是在掩膜mask控制下的"img1 + img2"结果。在计算时,掩码为1的部分对应"img1+img2",其他部分的像素值均为0。

注意:

​ 不仅是在图像的加法运算中会有使用掩膜的情况,在位运算等其他运算中也会有使用掩膜的情况。

​ 在之前的位运算中,将彩色的原始图像与掩膜图像进行计算,由于按位与操作要求参与运算的数据应该有相同的通道,所以无法直接将彩色图像与单通道的掩膜图像进行按位与操作。我们需要将掩膜图像转化为BGR模式的彩色图像,让彩色图像与(彩色)掩膜图像进行按位与操作,从而实现掩膜运算。

​ 实际上,在函数中所使用的掩膜参数可以是8位单通道图像。所以,可以将掩膜图像作为按位与函数cv2.bitwise_and(src1, src2 [, mask])中参数mask的值,完成掩膜运算。此时,让待处理的彩色图像同时作为函数cv2.bitwise_and(src1, src2 [, mask]) 的参数src1, src2,使用掩膜图像作为掩膜参数,完成按位与操作,即可得到由掩膜控制的彩色图像。

补充: 任何数值与滋生进行按位与计算,得到的仍是自身。

import cv2
import numpy as npimg1 = cv2.imread('../lena512color.tiff')
w, h, c = img1.shape
mask = np.zeros((w, h), dtype=np.uint8)
mask[100: 400, 200: 400] = 255
mask[100: 500, 100: 200] = 255
img2 = cv2.bitwise_and(img1, img1, mask=mask)
cv2.imshow('img1', img1)
cv2.imshow('mask', mask)
cv2.imshow('img2', img2)
cv2.waitKey()
cv2.destroyAllWindows()

在这里插入图片描述

five. 图像与数值运算:

在上述的加法运算和按位运算中,参与运算的的连个参数都是相同的,实际上既可以是两幅图像,也可以是一幅图像一个数值。

例如:如果想增加图像的整体亮度,可以将每一个像素值都加上一个特定的值。在实现时,可以个图像加上一个统一像素值的图像,也可以给图像加上一个固定值。

例1: img1 和 img2的原始值分别为:

image1=∣3333333333333333333333333∣image2=∣5555555555555555555555555∣image1 = \begin{vmatrix} 3 & 3 & 3 & 3 & 3 \\ 3 & 3 & 3 & 3 & 3 \\3 & 3 & 3 & 3 & 3 \\3 & 3 & 3 & 3 & 3 \\3 & 3 & 3 & 3 & 3 \end{vmatrix} \quad image2 = \begin{vmatrix} 5 & 5 & 5 & 5 & 5 \\ 5 & 5 & 5 & 5 & 5 \\5 & 5 & 5 & 5 & 5 \\5 & 5 & 5 & 5 & 5 \\5 & 5 & 5 & 5 & 5 \end{vmatrix}image1=3333333333333333333333333image2=5555555555555555555555555

  • img3 = cv2.add(img1, img2)运算后,得到img3为:

image3=∣8888888888888888888888888∣image3 = \begin{vmatrix} 8 & 8 & 8 & 8 & 8 \\ 8 & 8 & 8 & 8 & 8 \\8 & 8 & 8 & 8 & 8 \\8 & 8 & 8 & 8 & 8 \\8 & 8 & 8 & 8 & 8 \end{vmatrix}image3=8888888888888888888888888

  • img4 = cv2.add(img1, 6)运算后,得到img4为:

image4=∣9999999999999999999999999∣image4 = \begin{vmatrix} 9 & 9 & 9 & 9 & 9 \\ 9 & 9 & 9 & 9 & 9 \\9 & 9 & 9 & 9 & 9 \\9 & 9 & 9 & 9 & 9 \\9 & 9 & 9 & 9 & 9 \end{vmatrix}image4=9999999999999999999999999

  • img5 = cv2.add(6, img1)运算后,得到img5为:

image5=∣11111111111111111111111111111111111111111111111111∣image5 = \begin{vmatrix} 11 & 11 & 11 & 11 & 11 \\ 11 & 11 & 11 & 11 & 11 \\11 & 11 & 11 & 11 & 11 \\11 & 11 & 11 & 11 & 11 \\11 & 11 & 11 & 11 & 11 \end{vmatrix}image5=11111111111111111111111111111111111111111111111111

six. 位平面分解:

​ 将灰度图像中处于同一比特位上的二进制像素进行组合,得到一幅新的二进制图像,该图像称为灰度图像的一个位平面。这个过程称为位平面分解。例如,将一幅灰度图像内所有像素点上处于二进制位内最低为上的值进行组合,可以构成"最低有效位"位平面。

​ 在8位灰度图中,每一个像素都是使用8位二进制来表示,其值范围在[0, 255]之间,可以将其中值表示为:

在这里插入图片描述

式中,aia_iai 的可能只为0或1。可以看出,各个aia_iai的权重是不一样的,a7a_7a7的权重最高,a0a_0a0 的权重最低。这代表a7a_7a7 的值对图像的影响最大,而a0a_0a0 的值对图像影响最小。

​ 通过提取灰度图像像素点二进制像素值的每一比特位的组合,可以得到多个位平面图像。图像中全部像素值的aia_iai 值所构成的位平面,称为第i个位平面(第i层)。在8位灰度图中,可以组成8个二进制图像,即可以将原图分解成8个位平面。

​ 根据上述分析,像素值中各个aia_iai的权重是不一样的:

  • a7a_7a7的权重最高,所构成的位平面与原图像相关性最高,改位平面看起来通常原图像最类似
  • a0a_0a0 权重最低,所构成的位平面与原图像相关性最低,该平面看起来通常是杂乱无章的。

借助按位与运算可以实现位平面分解。例如,有灰度图像O的像素值为:

在这里插入图片描述

其对应的二进制值为:

在这里插入图片描述

将所有像素的aia_iai值进行组合,便会得到图像的8个位平面。a-h一次是a0−a7a_0 - a_7a0a7

在这里插入图片描述

​ 针对RGB图像,如果将R通道、G通道、B通道中的每一个通道对应的位平面进行合并,即可组成新的RGB彩色图像。例如,针对一幅RGB图像,将其R通道的第3个位平面、G通道的第3个位平面、B通道的第3个位平面进行合并,则可以构成一幅新的RGB彩色图像,我们称之为原始图像的第3个位平面。通过上述方式,可以完成对彩色图像的位平面分解。

以灰度图像为例,介绍位平面分解的具体步骤:

  1. 图像预处理:读取原始图像O,获取原始图像的宽M和高N

  2. 构造提取矩阵:使用按位与操作能够很方便的将一个数值指定位上的数字提取出来。例如,下图分别使用不同的提取因子F来提取数值N中的特定位。
    在这里插入图片描述

    根据上述分析结果来看,可以建立一个值均为2n2^n2n 的Mat作为提取矩阵,用来与原始图像进行按位与运算,以提取第n个位平面。

    提取矩阵Mat中的值可以是:
    在这里插入图片描述

  3. 提取位平面:

    将灰度图像与提取矩阵进行按位与运算,得到各个位平面。

    将像素值与一个值为2n2^n2n的数值进行按位与运算,能够保证像素值的第n位保持不变,而将其余各位均置0。因此,通过像素值与特定值的按位与运算,能够提取像素值的指定二进制位的值。同理,通过按位运算,能够提取图像的指定位平面。

    例如,有一个像素点的像素值为219,要提取其第4个二进制位的值,即提取该像素值的第4位信息(序号从0开始)。此时,需要借助的提取值是"242^424 = 16"。
    在这里插入图片描述

    例如:

    针对下图图像O提取位平面:

    在这里插入图片描述

    其对应的二进制形式为:

    在这里插入图片描述

    提取其中第3个位平面,则需要建立元素值均为232^323(8) 的提取矩阵:

    在这里插入图片描述

    将原图像与提取矩阵进行按位与运算得到:
    在这里插入图片描述

    补充: 提取位平面也可以通过将二进制像素值右移指定位,然后对2取模得到。例如要提取第n个位平面,可以将像素向右侧移动n位,然后对2取模,就可以得到第n个位平面。

  4. 阈值处理:

    ​ 通过计算得到的位平面是一个二值图像(即0值和特定值),如果直接将上述得到的位平面显示出来,则会得到一张近似黑色的图像。因为当前显示的是8位灰度图,当像素值较小时,显示的图像会近似黑色。

    ​ 也就是说,每次提取位平面后,要想让二值的位平面以黑白的颜色显示出来,就要将得到的二值位平面进行阈值处理,将其中不为0的数设置为255。

  5. 显示图像:

例题:提取一幅图像的各个位平面。

import cv2
import numpy as nplena = cv2.imread('../lena.bmp', 0)
cv2.imshow('lena', lena)
r, c = lena.shape
x = np.zeros((r, c, 8), dtype=np.uint8)
for i in range(8):x[:, :, i] = 2**i
r = np.zeros((r, c, 8), dtype=np.uint8)
for i in range(8):r[:, :, i] = cv2.bitwise_and(lena, x[:, :, i])mask = r[:, :, i] > 0r[mask] = 255cv2.imshow(str(i), r[:, :, i])
cv2.waitKey()
cv2.destroyAllWindows()

在这里插入图片描述

seven. 图像加密和解密:

通过对图像的按位异或运算可以实现图像的加密和解密。

通过对原始图像与密钥图像进行按位异或,可以实现加密;将加密后的图像与密钥图像再次进行按位异或,可以实现解密。

在这里插入图片描述

根据异或运算的规则,假设:

  • xor(a, b) = c

则,可以得到:

  • xor(c, b) = a

  • xor(c, a) = b

按位异或过程示例:

在这里插入图片描述

从上述结果看,a, b, c具有如下关系:

  • a:明文,原始数据
  • b:密钥
  • c:密文,通过xor(a, b)实现

则上诉数据的操作可以理解为:

  • 加密过程:将明文a与密钥b进行按位异或,完成加密,得到密文c
  • 解密过程:将密文c与密钥b进行按位异或,完成解密,得到明文a

位运算是指针对二进制位进行的运算,利用位运算即可实现对像素点的加解密。

在图像处理过程中,需要处理的图像像素点的值通常是灰度值,其方位是[0, 255]。例如,某个像素点的值是216(明文),则可以使用178(该值由加密者自定义),作为密钥对其进行加密,让这两个数的二进制值按位进行异或运算即完成加密,得到一个密文106。当需要解密时,将密文106与密钥178进行按位异或运算,即可得到原始像素点的值216。

  • bit_xor(216, 178) = 106
  • bit_xor(106, 178) = 216

加密过程:

在这里插入图片描述

解密过程:

在这里插入图片描述

对图像内的每一个像素点重复上述操作,即可完成对图像的加密、解密操作。

例题: 随机生成一幅图像作为密钥,对原始图像进行加密

import cv2
import numpy as nplena = cv2.imread('../lena.bmp', 0)
r, c = lena.shape
key = np.random.randint(0, 256, size=[r, c], dtype=np.uint8)
encryption = cv2.bitwise_xor(lena, key)
decryption = cv2.bitwise_xor(encryption, key)
cv2.imshow('lena', lena)
cv2.imshow('key', key)
cv2.imshow('encryption', encryption)
cv2.imshow('decryption', decryption)cv2.waitKey()
cv2.destroyAllWindows()

在这里插入图片描述

eight. 数字水印:

​ 最低有效位值二进制数值中第0位,即最低位。最低有效位信息隐藏指的是,将需要隐藏的二值图像信息,嵌入到载体图像的最低有效位,即将载体图像的最低有效位替换为当前需要隐藏的二值图像,从而实现二值图像隐藏的目的。由于二值图像处于载体的最低有效位上,所以对载体图像影响不明显,具有较高隐蔽性。

这种信息隐藏也被称为数字水印。通过该方式可以实现:

  • 信息隐藏
  • 版权认证
  • 身份认证

等功能,数字水印信息可以是文本、视频、音频等形式。

1. 原理:

从位平面的角度考虑,数字水印分为以下两部:

  • 嵌入过程:将数字水印信息(一幅二值图像)嵌入到载体图像的第0个位平面。

    例如,一幅灰度图像为:

    在这里插入图片描述

    其对应的二进制为:

    在这里插入图片描述

    有灰度二值图像W:

    在这里插入图片描述

    将一幅灰度二值水印图像W嵌其中得:

    在这里插入图片描述

    由于信息最低有效位对值的大小影响有限,因此图像不会发生明显变换,肉眼不可见

    为了便于理解这里仅介绍了载体图像为灰度图像的情况,在实际中可以根据需要在多个通道内嵌入相同的水印(提高鲁棒性),或在不同的通道嵌入不同的水印(提高嵌入量)等。

    • 注意:实际处理过程中,原始图像和水印图像是可以彩色图像,这时候需要先对他们进行通道分解,图层分解。然后在将数字水印嵌入到载体图像。
  • 提取过程:将载体图像的第0个位平面提取出来,得到数字水印。

    提取的过程就是嵌入的过程的逆运算。

2.实现方法:

最低有限位水印的实现 包括嵌入过程和提取过程,下面介绍其具体实现方法:

嵌入过程:

  1. 载体图像预处理:读取原始载体图像,并获取载体图像的行数M和列数N

  2. 建立提取矩阵:建立一个MxN大小、元素值均为254的提取矩阵。用来提取图像的高7位

  3. 通过按位与运算,提取载体图像的高7位,将最低位置0。

  4. 水印图像处理:某些情况下需要对水印图像进行简单处理,如当水印图像为8位灰度图的二值图像时,就需要将其转换为二进制的二值图像,以方便将其嵌入到载体图像的最低位。
    在这里插入图片描述

  5. 嵌入水印:将原始载体图像进行"保留高7位,最低位置零"操作后,我们能得到一幅新的图像,将新的图像与水印图像进行按位或运算,就能将水印信息嵌入到载体图像。

  6. 显示图像:完成上述操作后可以对原始图像、水印图像、含水印图像进行显示。
    在这里插入图片描述

提取过程:

  1. 含水印载体图像处理:读取含水印的载体图像,并获取含水印载体图像的大小MxN
  2. 建立提取矩阵:建议一个大小为MxN的,值均为1的提取矩阵。
  3. 提取水印信息:将含水印的载体图像与提取矩阵进行按位与操作,提取水印信息。
  4. 计算去除水印后的载体图像
  5. 显示图像
    在这里插入图片描述

注意:对像素值进行对2取模,可以获取像素值的最低有效位。因此可以通过对像素值进行对2取模的方式,来获取最低有效位的水印信息。

例如:模拟数字水印的嵌入和提取过程

import cv2
import numpy as nplena = cv2.imread('../lena.bmp', 0)
watemark = cv2.imread('../boat.512.tiff', 0)
w = watemark[:, :] > 0
watemark[w] = 1r, c = lena.shape
t254 = np.ones((r, c), dtype=np.uint8) * 254
lena_h7 = cv2.bitwise_and(lena, t254)
e = cv2.bitwise_or(lena_h7, watemark)
t1 = np.ones((r, c), dtype=np.uint8)
wm = cv2.bitwise_and(e, t1)w = wm[:, :] > 0
wm[w] = 255
cv2.imshow('lena', lena)
cv2.imshow('watemake', watemark*255)
cv2.imshow('e', e)
cv2.imshow('wm', wm)
cv2.waitKey()
cv2.destroyAllWindows()

注意:对像素值进行对2取模,可以获取像素值的最低有效位。因此可以通过对像素值进行对2取模的方式,来获取最低有效位的水印信息。

例如:模拟数字水印的嵌入和提取过程

import cv2
import numpy as nplena = cv2.imread('../lena.bmp', 0)
watemark = cv2.imread('../boat.512.tiff', 0)
w = watemark[:, :] > 0
watemark[w] = 1r, c = lena.shape
t254 = np.ones((r, c), dtype=np.uint8) * 254
lena_h7 = cv2.bitwise_and(lena, t254)
e = cv2.bitwise_or(lena_h7, watemark)
t1 = np.ones((r, c), dtype=np.uint8)
wm = cv2.bitwise_and(e, t1)w = wm[:, :] > 0
wm[w] = 255
cv2.imshow('lena', lena)
cv2.imshow('watemake', watemark*255)
cv2.imshow('e', e)
cv2.imshow('wm', wm)
cv2.waitKey()
cv2.destroyAllWindows()

该文章内容参考总结自《OpenCV轻松入门》这本书,详细内容可以参考这本书。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/400651.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JMS中的消息通信模型

1. MQ简介: 消息队列(Message Queue,简称MQ),是应用程序与应用程序之间的一种通信方法。应用程序通过发送和检索出入列队的针对应用程序的数据 - 消息来通信,而无需专用连接来链接它们。程序之间通过在消息中发送数据进…

【机器视觉学习笔记】最近邻插值实现图片任意角度旋转(C++)

目录原理源码RotateImage主函数效果完整源码速度优化源码优化效果平台:Windows 10 20H2 Visual Studio 2015 OpenCV 4.5.3 本文算法改进自图形算法与实战:6.图像运动专题(5)图像旋转-基于近邻插值的图像旋转 —— 进击的CV 原理…

UGUI的优点新UI系统

UGUI的优点新UI系统 第1章 新UI系统概述 UGUI的优点新UI系统,新的UI系统相较于旧的UI系统而言,是一个巨大的飞跃!有过旧UI系统使用体验的开发者,大部分都对它没有任何好感,以至于在过去的很长一段时间里,大…

【探索HTML5第二弹05】响应式布局(中),一步一步响应式布局

前言 前天初步探究了一次响应式布局,虽然花了一天功夫,做出来的东西还是不行,在此我还是认为要做响应式布局设计应该先行,应该先制作3个以上的设计图出来,但是对于手机来说,图片流量也是个问题,…

通过使用CSS字体阴影效果解决hover图片时显示文字看不清的问题

1.前言 最近需要加入一个小功能,在鼠标越过图片时,提示其大小和分辨率,而不想用增加属性title来提醒,不够好看。然而发现如果文字是一种颜色,然后总有概率碰到那张图上浮一层的文字会看不到,所以加入文字字…

第4章:色彩空间类型转换

第四章:色彩空间类型转换one. 色彩空间基础知识:1. GRAY色彩空间:2. XYZ色彩空间3. YCrCb色彩空间3. HSV色彩空间4. HLS 色彩空间5. CIEL * a * b *色彩空间6. CIEL * u * v *色彩空间7. Bayer色彩空间two. 类型转换函数:three. 类…

【机器视觉学习笔记】双线性插值实现图片任意角度旋转(C++)

目录原理源码RotateImage_BilinearInterpolation主函数效果与最近邻插值比较原图最近邻插值效果(局部)双线性插值效果(局部)完整源码平台:Windows 10 20H2 Visual Studio 2015 OpenCV 4.5.3 原理 如图所示&#xff0…

第5章 - 几何变换

第五章-几何变换one. 缩放:two. 翻转:three. 仿射:1. 平移:2. 旋转:3. 更多复杂的仿射变换:four. 透视:five. 重映射:1. 映射参数的理解:2. 复制:3. 绕x轴旋转&#xff1…

安装设置Android Studio Win7安装

发一下牢骚和主题无关: 让人等待已久的Google I/O 2013 大会没有给我们带来Android5.0,也没有带来Adnroid4.3等等,但带来了Android Studio,虽说是预览版,又是基于Intellij IDEA, 但是也无不让开辟者们高兴。…

【树莓派学习笔记】一、烧录系统、(无屏幕)配置Wifi和SSH服务

目录系统镜像的准备格式化TF卡烧录镜像配置Wifi开启SSH服务第一次开机平台:树莓派3B 版本: 2021-05-07-raspios-buster-armhf 系统镜像的准备 树莓派资源里有许多资源,包括我们要用到的镜像。 格式化TF卡 将TF卡格式化为FAT32格式。 …

第6章-阈值处理

第六章-阈值处理one. threshold函数:1. 二值化阈值处理(cv2.THRESH_BINARY):2. 反二值化阈值处理(cv2.THRESH_BINARY_INV)3. 截断阈值化处理(cv2.THRESH_TRUNC)4. 超阈值零处理(cv2.THRESH_TOZERO_INV)5.低阈值零处理(cv2.THRESH_…

【树莓派学习笔记】二、(无屏幕)SSH远程登录、图形界面及系统配置

目录确定树莓派LAN IP使用PuTTY登陆带图形界面的远程登陆Xming方案VNC Server 方案系统配置换源(可选)备份原文件查询系统版本编辑sources.list文件同步更新源更新软件包重启树莓派固定LAN IP平台:树莓派3B 版本: 2021-05-07-raspios-buster-armhf 确定…

Centos7完全分布式搭建Hadoop2.7.3

(一)软件准备 1,hadoop-2.7.3.tar.gz(包) 2,三台机器装有cetos7的机子 (二)安装步骤 1,给每台机子配相同的用户 进入root : su root 创建用户s: useradd s 修改用户密码:passwd s 2…

第7章:图像的平滑处理

第7章:图像的平滑处理一、均值滤波:二、方框滤波:三、高斯滤波:四、中值滤波五、双边滤波:六、2D卷积​ 图像的平滑处理是在尽量图像原有信息的情况下,过滤掉图像内部的噪声。由于图像平滑处理的同时通常伴…

【树莓派学习笔记】三、点亮一个LED灯(C语言 - WiringPi、Python - RPi.GPIO/GPIO Zero、bash脚本)

目录C语言WiringPiPythonRPi.GPIOGPIO Zerobash脚本平台:树莓派3B 版本: 2021-05-07-raspios-buster-armhf 若GPIO输出为3.3V 采用压降为1.7V的红色LED灯 设工作电流为15mA,则限流电阻取≥(3.3 - 1.7)/0.015 106.67欧较为安全。 C语言 Wi…

OpenStack 之Nova添加扩展API流程,附带资源的查找功能

例子中涉及到SQLAlchemy 得相关操作,可以参考 上一随笔 Openstack 中规定,扩展openstack得api有两种方式 创建新的WSGI 资源扩展原有得WSGI资源得控制器(我得理解是,接受到API请求后,具体得响应逻辑)这两种…

第8章:形态学操作

第8章:形态学操作one. 腐蚀操作:two. 膨胀:three. 通用形态学函数:four. 开运算:five. 闭运算:six. 形态学梯度运算:seven. 礼帽运算:eight. 黑帽运算:night. 核函数&…

【树莓派学习笔记】四、OpenCV的安装与卸载

目录安装修改host以连接上Github测试IP修改树莓派的hosts安装各种依赖包安装OpenCV只安装核心模块安装核心模块和opencv_contribC Opencv 测试编写测试源码编译测试卸载平台:树莓派3B 版本: 2021-05-07-raspios-buster-armhf 安装 修改host以连接上Git…

第9章:图像梯度

第9章:图像梯度one. Sobel理论基础1. 计算水平方向偏导数的近似值2. 计算垂直方向偏导数的近似值two. Sobel算子及函数的使用:1. 函数语法:2. 对像素取绝对值:3. 方向:three. Scharr 算子及函数使用:1. 函数语法:2. 实…

【树莓派学习笔记】五、处理、自动重命名并另存为图片

目录编写源码编译测试平台&#xff1a;树莓派3B 版本&#xff1a; 2021-05-07-raspios-buster-armhf 编写源码 所用源码修改自【机器视觉学习笔记】最近邻插值实现图片任意角度旋转&#xff08;C&#xff09; 在合适的地方编写源码 nano main.cpp#include <opencv2/openc…