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)进行按位或运算得到的。
OpenCV程序练习(三):图像运算的更多相关文章
- OpenCV学习笔记(一)安装及运行第一个OpenCV程序
1.下载及安装 OpenCV是一套开源免费的图形库,主要有C/C++语言编写,官网: http://opencv.org/ .在 http://opencv.org/downloads.html 可以 ...
- openCV学习——一、图像读取、显示、输出
openCV学习——一.图像读取.显示.输出 一.Mat imread(const string& filename,int flags=1),用于读取图片 1.参数介绍 filename ...
- 使用VS2017 编写Linux系统上的Opencv程序
背景 之前写图像算法的程序都是在window10下使用VS编写,VS这个IDE结合“ImageWatch.vsix“插件,用于调试opencv相关的图像算法程序十分方便.后因项目需要,需将相关程序移植 ...
- Ubuntu系统---编译opencv程序的几种方式g++、Makefile、Cmake
Ubuntu系统---编译opencv程序的几种方式g++.Makefile.Cmake 先建立一个工程(一个文件夹),写好xxx.cpp文件,可以是多个: //----------opencv.cp ...
- Python下opencv使用笔记(图像频域滤波与傅里叶变换)
Python下opencv使用笔记(图像频域滤波与傅里叶变换) 转载一只程序喵 最后发布于2018-04-06 19:07:26 阅读数 1654 收藏 展开 本文转载自 https://blog ...
- OpenCV 第二课 认识图像的存储结构
OpenCV 第二课 认识图像的存储结构 Mat Mat 类包含两部分,矩阵头和矩阵体.矩阵头包含矩阵的大小,存储方式和矩阵体存储空间的指针.因此,Mat中矩阵头的大小是固定的,矩阵体大小是不定的. ...
- python函数,lambda表达式,三目运算,列表解析,递归
一.自定义函数 定义函数时,函数体不执行:只有在调用函数时,函数体才执行.函数的结构: 1. def 2. 函数名 3. 函数体 def func_name(): 函数体 4. 返回值 如果没有声明返 ...
- opencv笔记4:模板运算和常见滤波操作
time:2015年10月04日 星期日 00时00分27秒 # opencv笔记4:模板运算和常见滤波操作 这一篇主要是学习模板运算,了解各种模板运算的运算过程和分类,理论方面主要参考<图像工 ...
- opencv笔记2:图像ROI
time:2015年 10月 03日 星期六 12:03:45 CST # opencv笔记2:图像ROI ROI ROI意思是Region Of Interests,感兴趣区域,是一个图中的一个子区 ...
- if 结构和三目运算和switch语句
if语句需要注意的地方: if判断只能接一个语句,存在多个语句时,用块语句表示{},若在if判断后 直接加“:”相当于if判断后加一个空语句,即使条件成立什么也不会干! 1. if的第一种形态(真假) ...
随机推荐
- pikachu靶机练习平台-xss
第一题:反射性xss(get) 输出的字符出现在url中 第二题:反射性xss(post) 登录后输入<script>alert(1)</script> 第三题:存储型xss ...
- Nginx 常用的基础配置(web前端相关方面)
文章出处:https://juejin.cn/post/7196859948554715195 基础配置 user root; worker_processes 1; events { worker_ ...
- 面向K-12学生的远程访问学校计算机实验室
为了应对新冠肺炎大流行,许多学校被迫采用远程学习和混合时间制度.在家学习的学生必须使用自己的个人设备或学校提供的设备(例如 Chromebook )来完成课堂作业. 尽管许多解决方案可以帮助学生和 ...
- 10分钟了解Flink SQL使用
Flink 是一个流处理和批处理统一的大数据框架,专门为高吞吐量和低延迟而设计.开发者可以使用SQL进行流批统一处理,大大简化了数据处理的复杂性.本文将介绍Flink SQL的基本原理.使用方法.流批 ...
- 用 C 语言开发一门编程语言 — 基于 Lambda 表达式的函数设计
目录 文章目录 目录 前文列表 函数 Lambda 表达式 函数设计 函数的存储 实现 Lambda 函数 函数的运行环境 函数调用 可变长的函数参数 源代码 前文列表 <用 C 语言开发一门编 ...
- 来自多彩世界的控制台——C#控制台输出彩色字符画
引言 看到酷安上有这样一个活动,萌生了用 C# 生成字符画的想法,先放出原图. 酷安手绘牛啤 §1 黑白 将图像转换成字符画在 C# 中很简单,思路大致如下: 加载图像,逐像素提取明度. ...
- STM32WB55 BLE双核flash擦写程序深度解析
简介 STM32WB55的flash擦除有两种机制,一种是只有单核运行下的flash擦除,这种模式下,flash擦除的步骤同其他STM32的flash擦除一样,直接调用HAL库中flash擦除的库函数 ...
- itest(爱测试)开源接口测试&敏捷测试&极简项目管理 8.0.0 发布,测试重大升级
(一)itest 简介及更新说明 itest 开源敏捷测试管理,testOps 践行者,极简的任务管理,测试管理,缺陷管理,测试环境管理,接口测试,接口Mock 6合1,又有丰富的统计分析.可按测试包 ...
- 解决 idea web项目没有小蓝点的问题
在idea导入web项目,项目没有显示小蓝点,无法添加 java文件和运行.如下图的springboot-schedule 和 springboot-test 都没有蓝点: 解决方案一: 点击 Fil ...
- c# winfrom DataGridView 动态UI下载功能(内含GIF图) || 循环可变化的集合 数组 datatable 等
Gif演示 分解步骤 1,使用组件DataGridView 2,使用DataSource来控制表格展示的数据来源(注意:来源需要是DataTable类型) 3,需要用到异步线程.如果是不控制数据源的话 ...
