一、图像加法运算

代码

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)进行按位或运算得到的。

OpenCV程序练习(三):图像运算的更多相关文章

  1. OpenCV学习笔记(一)安装及运行第一个OpenCV程序

    1.下载及安装 OpenCV是一套开源免费的图形库,主要有C/C++语言编写,官网: http://opencv.org/ .在 http://opencv.org/downloads.html 可以 ...

  2. openCV学习——一、图像读取、显示、输出

    openCV学习——一.图像读取.显示.输出   一.Mat imread(const string& filename,int flags=1),用于读取图片 1.参数介绍 filename ...

  3. 使用VS2017 编写Linux系统上的Opencv程序

    背景 之前写图像算法的程序都是在window10下使用VS编写,VS这个IDE结合“ImageWatch.vsix“插件,用于调试opencv相关的图像算法程序十分方便.后因项目需要,需将相关程序移植 ...

  4. Ubuntu系统---编译opencv程序的几种方式g++、Makefile、Cmake

    Ubuntu系统---编译opencv程序的几种方式g++.Makefile.Cmake 先建立一个工程(一个文件夹),写好xxx.cpp文件,可以是多个: //----------opencv.cp ...

  5. Python下opencv使用笔记(图像频域滤波与傅里叶变换)

    Python下opencv使用笔记(图像频域滤波与傅里叶变换) 转载一只程序喵 最后发布于2018-04-06 19:07:26 阅读数 1654  收藏 展开 本文转载自  https://blog ...

  6. OpenCV 第二课 认识图像的存储结构

    OpenCV 第二课 认识图像的存储结构 Mat Mat 类包含两部分,矩阵头和矩阵体.矩阵头包含矩阵的大小,存储方式和矩阵体存储空间的指针.因此,Mat中矩阵头的大小是固定的,矩阵体大小是不定的. ...

  7. python函数,lambda表达式,三目运算,列表解析,递归

    一.自定义函数 定义函数时,函数体不执行:只有在调用函数时,函数体才执行.函数的结构: 1. def 2. 函数名 3. 函数体 def func_name(): 函数体 4. 返回值 如果没有声明返 ...

  8. opencv笔记4:模板运算和常见滤波操作

    time:2015年10月04日 星期日 00时00分27秒 # opencv笔记4:模板运算和常见滤波操作 这一篇主要是学习模板运算,了解各种模板运算的运算过程和分类,理论方面主要参考<图像工 ...

  9. opencv笔记2:图像ROI

    time:2015年 10月 03日 星期六 12:03:45 CST # opencv笔记2:图像ROI ROI ROI意思是Region Of Interests,感兴趣区域,是一个图中的一个子区 ...

  10. if 结构和三目运算和switch语句

    if语句需要注意的地方: if判断只能接一个语句,存在多个语句时,用块语句表示{},若在if判断后 直接加“:”相当于if判断后加一个空语句,即使条件成立什么也不会干! 1. if的第一种形态(真假) ...

随机推荐

  1. Kimi:文本解析利器,你相信光么?

    缘起 第一次接触 kimi 是在微信群,开始以为是推广薅羊毛产品,后来在其他渠道也了解到 kimi,据说是"国产之光".我知道很多同学苦不能使用魔法久矣,索性就先踩踩这个" ...

  2. Ubuntu实现与主机Windows复制粘贴(安装VMware Tools)

    若不能实现主机与客户机间粘贴复制执行以下命令 sudo apt-get autoremove open-vm-tools sudo apt-get install open-vm-tools sudo ...

  3. python教程6.5-excel处理模块

    第三方开源模块安装  创建文件 打开已有文件 写数据 选择表 保存表 遍历表 按行遍历 按列遍历 遍历指定行列 遍历指定第几列数据 删除表 设置单元格样式 字体 对齐 设置行高列宽

  4. IceRPC之传入响应和拦截器

    作者引言 .Net 8.0 下的新RPC 很高兴啊,我们来到了IceRPC之传入响应和拦截器->快乐的RPC, 基础引导,让自已不在迷茫,快乐的畅游世界. 传入响应 Incoming respo ...

  5. Dapr 与 .NET Aspire 结合使用获得无与伦比的本地开发体验

    Dapr 提供了一组构建块,用于抽象分布式系统中常用的概念.这包括服务.缓存.工作流.复原能力.机密管理等之间的安全同步和异步通信.不必自己实现这些功能,可以消除样板,降低复杂性,并允许您专注于开发业 ...

  6. 安卓开发封装处理Retrofit协程请求中的异常

    上篇文章讲解了怎么使用Kotlin的协程配合Retrofit发起网络请求,使用也是非常方便,但是在处理请求异常还不是很人性化.这篇文章,我们将处理异常的代码进行封装,以便对异常情况返回给页面,提供更加 ...

  7. 简单粗暴通过 Binlog 日志来恢复 MySQL 数据

    引言 Binlog 日志的主要作用: 1.增量备份. 2.主从复制. 操作步骤 1.登录 MySQL -> 执行 show variables like '%log_bin%'; 查询 binl ...

  8. Android 12(S) MultiMedia(十四)ESQueue

    之前看到在ATSParser::Pogram::Stream中会创建一个ESQueue,用于存储解析出来的ES data,这个ESQueue到底是用来做什么的呢?这节就来研究研究. 1.构造函数 ES ...

  9. kubernetes的三种探针startupprobe,ReadinessProbe,LivenessProbe记录

    kubernetes的三种探针 startupprobe: k8s1.16版本后新加的探测方式,用于判断容器内应用程序是否已经启动,如果配置了startuprobe,就会先禁用其他的探测,直到它成功为 ...

  10. Qt-FFmpeg开发-音频解码为PCM文件(9)

    音视频/FFmpeg #Qt Qt-FFmpeg开发-使用libavcodec API的音频解码示例(MP3转pcm) 目录 音视频/FFmpeg #Qt Qt-FFmpeg开发-使用libavcod ...