OpenCV程序练习(三):图像运算

一、图像加法运算

代码

import cv2

img=cv2.imread("demoimg.jpg",0) #读取图片,参数0等价于cv2.IMREAD_GRAYSCALE,将图像调整为单通道的灰度图像
#分别用“+”运算符和cv2.add()函数处理图像
result1=img+img
result2=cv2.add(img,img)
#显示图像
cv2.imshow("original image",img)
cv2.imshow("+operation",result1)
cv2.imshow("add()operation",result2)

#----------释放窗口---------
cv2.waitKey()
cv2.destroyAllWindows()

运行结果

程序分析

  • +运算符处理图像时,会将和大于255的像素值进行取模处理,使相加后本应变得更亮的像素点变得更暗。
  • cv2.add()函数处理图像时,会将和大于255的像素值处理为饱和值255,使相加后图像整体变亮。

 

二、图像加权和

代码

import cv2

#读取图像
img1=cv2.imread("demoimg.jpg")
img2=cv2.imread("demoimg2.jpg")
result=cv2.addWeighted(img1, 0.6, img2, 0.5, 0) #图像加权混合,第二个和第四个参数为图像对应的系数,其和可以等于1也可以不等于1;最后一个参数为亮度调节亮,是必选参数
#显示图像
cv2.imshow("image1",img1)
cv2.imshow("image2",img2)
cv2.imshow("result",result)

#----------释放窗口---------
cv2.waitKey()
cv2.destroyAllWindows()

运行结果

代码分析

cv2.addWeighted()函数可理解为结果图像=图像1×系数1+图像2×系数2+亮度调节量,其中亮度调节量为正值时图像偏亮,为负值时图像偏暗。

 

三、掩模图像

1、灰度图像

代码

import cv2
import numpy as np

img=cv2.imread("demoimg.jpg",0)  #读取图像,参数“0”将图像调整为灰度模式
mask=np.zeros(img.shape,dtype=np.uint8) #创建掩模图像,img.shape:获取该灰度图像的行数、列数
mask[170:220,110:160]=255   #保留ROI
x=cv2.bitwise_and(img,mask) #将原始图像和掩模图像进行按位与运算
#打印原始图像和掩模图像的属性
print("img.shape=",img.shape)
print("mask.shape=",mask.shape)
#显示图像
cv2.imshow("original image",img)
cv2.imshow("mask",mask)
cv2.imshow("bitwise_and",x)

#----------释放窗口---------
cv2.waitKey()
cv2.destroyAllWindows()

运行结果

2、彩色图像

代码

import cv2
import numpy as np

img=cv2.imread("demoimg.jpg",1)  #读取图像,参数“1”等价于cv2.IMREAD_COLOR,将图像调整为3通道的BGR图像,该值是默认值
w,h,c=img.shape #获取图像的行数、列数、通道数
mask=np.zeros((w,h,c),dtype=np.uint8)   #创建掩模图像,(w,h,c)可直接写为img.shape
mask[170:220,110:160]=255   #保留ROI
x=cv2.bitwise_and(img,mask) #将原始图像和掩模图像进行按位与运算
#打印原始图像和掩模图像的属性
print("img.shape=",img.shape)
print("mask.shape=",mask.shape)
#显示图像
cv2.imshow("original image",img)
cv2.imshow("mask",mask)
cv2.imshow("bitwise_and",x)

#----------释放窗口---------
cv2.waitKey()
cv2.destroyAllWindows()

运行结果

3、程序分析

按位与操作要求参与运算的数据有相同的通道,无法直接将彩色图像直接与单通道的掩模图像进行按位与操作。一般情况下,可以通过将掩模图像转换为BGR模式的彩色图像,让彩色图像与掩模图像进行按位与操作,实现掩模运算。可以直接通过语句mask=np.zeros(img.shape,dtype=np.uint8) ,生成和原图像属性相同的掩模图像。

 

四、位平面分解

代码

import cv2
import numpy as np

#---------------①图像预处理---------------
img=cv2.imread("demoimg.jpg",0)     #读取图像为灰度模式
cv2.imshow("original image",img)    #显示原图像
#---------------②构造提取矩阵---------------
a,b=img.shape   #获取原图像属性参数
x=np.zeros((a,b,8),dtype=np.uint8)  #设置一个用于提取各个位平面的的提取矩阵。该矩阵大小为: 行高a × 列宽b × 8个通道
#第一个for循环提取各个位平面的提取矩阵的值
for i in range(8):
    x[:,:,i]=2**i
#第二个for循环实现各个位平面的提取、阈值处理和显示
y=np.zeros((a,b,8),dtype=np.uint8)
for i in range(8):
    # ---------------③提取位平面---------------
    y[:,:,i]=cv2.bitwise_and(img,x[:,:,i])
    # ---------------④阈值处理---------------
    mask=y[:,:,i]>0     #将y中大于0的值处理为True,小于或等于0的值处理为False
    y[mask]=255     #将mask中为True的值替换为255
    # ---------------⑤显示图像---------------
    cv2.imshow(str(i),y[:,:,i])

#----------释放窗口---------
cv2.waitKey()
cv2.destroyAllWindows()

运行结果

程序分析

● 阈值处理:
通过计算得到的位平面是一个二值图像,如果直接将上述得到的位平面显示出来,则会得到一张近似黑色的图像。这是因为默认当前显示的图像是8位灰度图,而当其中的像素值较小时,显示的图像就会是近似黑色的,最大的像素值是8,因此几乎为纯黑色。要想让8显示为白色,必须将8处理为255。
● 运行结果分析:
在8位灰度图中,每一个像素使用8位二进制值来表示,其值的范围在[0,255]之间。可以将其中的值表示为: value=a7×2^7+a6×2^6+a5×2^5+a4×2^4+a3×2^3+a2×2^2+a1×2^1+a0×2^0
在运行结果显示的八个分解的位平面中,第7个位平面位于8位二进制值的最高位,其对像素值的影响最大。第7位二进制值在8位二进制数中权重最高,与原图像的相关度最高。所以,第7个位平面是与原始图像最接近的二值图像。

 

五、图像加密和解密

代码

import cv2
import numpy as np

img=cv2.imread("demoimg.jpg")     #读取图像
a,b,c=img.shape   #获取原图像属性参数
key=np.random.randint(0,256,size=[a,b,c],dtype=np.uint8)  #使用随机数生成密钥
encryption=cv2.bitwise_xor(img,key)     #加密图像:原图像和密钥进行按位异或运算
decryption=cv2.bitwise_xor(encryption,key)  #解密图像:加密图像和密钥按位异或运算
#显示图像
cv2.imshow("original image",img)
cv2.imshow("key",key)
cv2.imshow("encryption",encryption)
cv2.imshow("decryption",decryption)


#----------释放窗口---------
cv2.waitKey()
cv2.destroyAllWindows()

运行结果

程序分析

  • 加密和解密过程首先需要一个密钥作为媒介,加密过程是原图像和密钥进行按位异或运算,解密过程是加密图像和密钥进行按位异或运算。
  • 密钥内的参数size必须和原图像的shape相同,可直接通过语句key=np.random.randint(0,256,img.shape,dtype=np.uint8),生成与原图像属性相同的随机密钥。

 

六、数字水印

1、嵌入提取水印

代码

import cv2
import numpy as np

#==============================载体图像预处理==============================
img=cv2.imread("demoimg.jpg",1)      #读取3通道BGR模式的原始图像
watermark=cv2.imread("logo.jpg",1)  #读取3通道BGR模式的水印图像

#==============================嵌入过程==============================
#---------------①建立提取矩阵---------------
t254=np.ones(img.shape,dtype=np.uint8)*254  #生成元素值都是254(1111 1110)的数组,大小和原图像的shape相同
#---------------②保留载体图像的高七位,将最低为置零---------------
imgH7=cv2.bitwise_and(img,t254)     #获取原图像的高七位
#---------------③水印图像处理---------------
#将水印图像内的值255处理为1,以方便嵌入
w=watermark[:,:]>0  #将watermark中大于0的值处理为True,小于或等于0的值处理为False
watermark[w]=1  #将w中True的部分替换为1
#---------------④嵌入水印---------------
markimage=cv2.bitwise_or(imgH7,watermark)   #将watermark嵌入imgH7内

#==============================提取过程==============================
#---------------①建立提取矩阵---------------
t1=np.ones(img.shape,dtype=np.uint8)    #生成元素值都是1的数组,大小和原图像的shape相同
#---------------②提取水印信息---------------
watermarkExtraction=cv2.bitwise_and(markimage,t1)   #从载体图像内提取水印图像
#---------------③计算去除水印后的载体图像---------------
#将水印图像内的值1处理为255,以方便显示
w=watermarkExtraction[:,:]>0    #将watermarkExtraction中大于0的值处理为True,小于或等于0的值处理为False
watermarkExtraction[w]=255  #将w中True的部分替换为255

#==============================显示图像==============================
cv2.imshow("original image",img)
cv2.imshow("watermark",watermark*255)   #当前watermark内最大值为1
cv2.imshow("markimage",markimage)

#==============================释放窗口==============================
cv2.waitKey()
cv2.destroyAllWindows()

运行结果

出现问题

    markimage=cv2.bitwise_or(imgH7,watermark)   #将watermark嵌入imgH7内
    cv2.error: OpenCV(4.0.1) C:\ci\opencv-suite_1573470242804\work\modules\core\src\arithm.cpp:229: error: (-209:Sizes of input arguments do not match) The operation is neither 'array op array' (where arrays have the same size and type), nor 'array op scalar', nor 'scalar op array' in function 'cv::binary_op'

原因分析

进行按位或运算的原图像和水印图像大小不同。

解决方法

将水印图像的大小调整为和原图像大小一致,再将两者进行按位或运算。

2、水印图像位平面分解

代码

import cv2
import numpy as np

#==============================载体图像预处理==============================
img=cv2.imread("demoimg.jpg",0)      #读取灰度模式的原始图像
watermark=cv2.imread("logo.jpg",0)  #读取灰度模式的水印图像

#==============================嵌入过程==============================
#---------------①建立提取矩阵---------------
t254=np.ones(img.shape,dtype=np.uint8)*254  #生成元素值都是254(1111 1110)的数组,大小和原图像的shape相同
#---------------②保留载体图像的高七位,将最低为置零---------------
imgH7=cv2.bitwise_and(img,t254)     #获取原图像的高七位
#---------------③水印图像处理---------------
#将水印图像内的值255处理为1,以方便嵌入
w=watermark[:,:]>0  #将watermark中大于0的值处理为True,小于或等于0的值处理为False
watermark[w]=1  #将w中True的部分替换为1
#---------------④嵌入水印---------------
markimage=cv2.bitwise_or(imgH7,watermark)   #将watermark嵌入imgH7内
#---------------⑤显示图像---------------
cv2.imshow("original image",img)
cv2.imshow("markimage",markimage)

#==============================位平面分解==============================
#---------------①构造提取矩阵---------------
a,b=markimage.shape   #获取markimage图像属性参数
x=np.zeros((a,b,8),dtype=np.uint8)  #设置一个用于提取各个位平面的的提取矩阵。该矩阵大小为: 行高a × 列宽b × 8个通道
#第一个for循环提取各个位平面的提取矩阵的值
for i in range(8):
    x[:,:,i]=2**i
#第二个for循环实现各个位平面的提取、阈值处理和显示
y=np.zeros((a,b,8),dtype=np.uint8)
for i in range(8):
    # ---------------②提取位平面---------------
    y[:,:,i]=cv2.bitwise_and(markimage,x[:,:,i])
    # ---------------③阈值处理---------------
    mask=y[:,:,i]>0     #将y中大于0的值处理为True,小于或等于0的值处理为False
    y[mask]=255     #将mask中为True的值替换为255
    # ---------------④显示图像---------------
    cv2.imshow(str(i),y[:,:,i])

#==============================释放窗口==============================
cv2.waitKey()
cv2.destroyAllWindows()

运行结果

程序分析

将8位灰度的嵌入水印的图像位平面分解后,可以看到只有第0个通道被替换为水印图像。将水印图像和原图像比较,通过肉眼无法观察出含水印载体图像和原始图像的不同,水印的隐蔽性较高。

 

七、对ROI打码及解码

代码

import cv2
import numpy as np

img=cv2.imread("demoimg.jpg")   #读取原始载体图像
mask=np.zeros(img.shape,dtype=np.uint8) #创建img.shape大小的掩模图像
mask[170:220,110:160]=1     #保留ROI
key=np.random.randint(0,256,size=img.shape,dtype=np.uint8)  #获取一个key,打码、解码所使用的密钥
#====================获取打码ROI====================
imgXorKey=cv2.bitwise_xor(img,key)  #使用密钥key对原始图像img加密
encryptROI=cv2.bitwise_and(imgXorKey,mask*255)  #获取加密图像ROI部位的信息encryptROI
noROI1=cv2.bitwise_and(img,(1-mask)*255) #将图像img内的ROI部位设置位0,得到noROI
maskROI=encryptROI+noROI1    #得到打码的img图像
#====================将打码ROI解码====================
extractOriginal=cv2.bitwise_xor(maskROI,key)    #将ROI部位打码的img与密钥key进行异或运算,得到ROI部位的原始信息
extractROI=cv2.bitwise_and(extractOriginal,mask*255)    #将解码的ROI部位信息extractOriginal提取出来,得到extractROI
noROI2=cv2.bitwise_and(maskROI,(1-mask)*255)    #从ROI部位打码的img内提取没有ROI部位信息的img图像,得到noROI2
extractImg=noROI2+extractROI    #得到解码的img图像
#====================显示图像====================
cv2.imshow("original image",img)
cv2.imshow("mask",mask*255)
cv2.imshow("1-mask",(1-mask)*255)
cv2.imshow("key",key)
cv2.imshow("imgXorKey",imgXorKey)
cv2.imshow("encryptROI",encryptROI)
cv2.imshow("noROI1",noROI1)
cv2.imshow("maskROI",maskROI)
cv2.imshow("extractOriginal",extractOriginal)
cv2.imshow("extractROI",extractROI)
cv2.imshow("noROI2",noROI2)
cv2.imshow("extractImg",extractImg)

#====================释放窗口====================
cv2.waitKey()
cv2.destroyAllWindows()

运行结果

运行结果分析

  • original image:原始图像。
  • mask:掩模图像。
  • 1-mask:掩模图像的反色图。
  • key:随机数生成的密钥。
  • imgXorKey:整体打码图像。是将原图像(img)和密钥图像(key)进行异或运算得到的。
  • encryptROI:从整体打码图像(imgXorKey)内提取的ROI部位打码图像(encryptROI)。
  • noROI1:从原图像(img)内提取的不包含ROI部位信息的图像(noROI1),在提取过程中以模板图像(mask)的反色图(1-mask)作为模板。
  • maskROI:对原图像(img)的ROI部位进行打码的结果图像(maskROI),该图像是通过对ROI部位打码图像(encryptROI)和不包含ROI部位信息的图像(noROI1)进行按位或运算得到的。
  • extractOriginal:提取的初步原始图像(extractOriginal)。该图像是通过对打码ROI部位图像(maskROI)和密钥图像(key)进行异或运算得到的。
  • extractROI:是从提取的初步原始图像(extractOriginal)中提取的ROI部位图像(extractROI)。
  • noROI2:从ROI部位打码的结果图像(maskROI)内提取的不包含ROI部位信息的图像(noROI2)。
  • extractImg:最终的ROI部位解码结果图像(extractImg)。该图像是通过对提取的ROI部位图像(extractROI)和不包含ROI部位信息的图像(noROI2)进行按位或运算得到的。
posted @ 2022-08-13 15:27  香菜大魔法师  阅读(139)  评论(0编辑  收藏  举报