[Python图像处理] 三十五.OpenCV图像处理入门、算数逻辑运算与图像融合(推荐)

该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门、OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子、图像增强技术、图像分割等,后期结合深度学习研究图像识别、图像分类应用。希望文章对您有所帮助,如果有不足之处,还请海涵~

前面一篇文章介绍了数字图像处理基础知识,包括像素及常见图像分类、OpenCV配置、常见数据类型、Numpy和Matplotlib绘制、几何图形绘制等。这篇文章将介绍OpenCV图像处理入门知识、算数逻辑运算与图像融合,万字长文整理,希望对您有所帮助。同时,该部分知识均为作者查阅资料撰写总结,并且开设成了收费专栏,为小宝赚点奶粉钱,感谢您的抬爱。当然如果您是在读学生或经济拮据,可以私聊我给你每篇文章开白名单,或者转发原文给你,更希望您能进步,一起加油喔~

前文参考:
[Python图像处理] 一.图像处理基础知识及OpenCV入门函数
[Python图像处理] 二.OpenCV+Numpy库读取与修改像素
[Python图像处理] 三.获取图像属性、兴趣ROI区域及通道处理
[Python图像处理] 四.图像平滑之均值滤波、方框滤波、高斯滤波及中值滤波
[Python图像处理] 五.图像融合、加法运算及图像类型转换
[Python图像处理] 六.图像缩放、图像旋转、图像翻转与图像平移
[Python图像处理] 七.图像阈值化处理及算法对比
[Python图像处理] 八.图像腐蚀与图像膨胀
[Python图像处理] 九.形态学之图像开运算、闭运算、梯度运算
[Python图像处理] 十.形态学之图像顶帽运算和黑帽运算
[Python图像处理] 十一.灰度直方图概念及OpenCV绘制直方图
[Python图像处理] 十二.图像几何变换之图像仿射变换、图像透视变换和图像校正
[Python图像处理] 十三.基于灰度三维图的图像顶帽运算和黑帽运算
[Python图像处理] 十四.基于OpenCV和像素处理的图像灰度化处理
[Python图像处理] 十五.图像的灰度线性变换
[Python图像处理] 十六.图像的灰度非线性变换之对数变换、伽马变换
[Python图像处理] 十七.图像锐化与边缘检测之Roberts算子、Prewitt算子、Sobel算子和Laplacian算子
[Python图像处理] 十八.图像锐化与边缘检测之Scharr算子、Canny算子和LOG算子
[Python图像处理] 十九.图像分割之基于K-Means聚类的区域分割
[Python图像处理] 二十.图像量化处理和采样处理及局部马赛克特效
[Python图像处理] 二十一.图像金字塔之图像向下取样和向上取样
[Python图像处理] 二十二.Python图像傅里叶变换原理及实现
[Python图像处理] 二十三.傅里叶变换之高通滤波和低通滤波
[Python图像处理] 二十四.图像特效处理之毛玻璃、浮雕和油漆特效
[Python图像处理] 二十五.图像特效处理之素描、怀旧、光照、流年以及滤镜特效
[Python图像处理] 二十六.图像分类原理及基于KNN、朴素贝叶斯算法的图像分类案例
[Python图像处理] 二十七.OpenGL入门及绘制基本图形(一)
[Python图像处理] 二十八.OpenCV快速实现人脸检测及视频中的人脸
[Python图像处理] 二十九.MoviePy视频编辑库实现抖音短视频剪切合并操作
[Python图像处理] 三十.图像量化及采样处理万字详细总结(推荐)
[Python图像处理] 三十一.图像点运算处理两万字详细总结(灰度化处理、阈值化处理)
[Python图像处理] 三十二.傅里叶变换(图像去噪)与霍夫变换(特征识别)万字详细总结
[Python图像处理] 三十三.图像各种特效处理及原理万字详解(毛玻璃、浮雕、素描、怀旧、流年、滤镜等)
[Python图像处理] 三十四.数字图像处理基础与几何图形绘制万字详解(推荐)
[Python图像处理] 三十五.OpenCV图像处理入门、算数逻辑运算与图像融合(推荐)


本文主要讲解Python调用OpenCV中的函数实现图像处理的基础知识,包括读取和显示图像、修改和保存图像、获取图像属性及通道、图像类型转换、获取图像ROI区域、图像加法运算和图像融合处理等知识。

一.OpenCV基础操作

1.读取显示图像

在第34篇文章中我们讲解了OpenCV显示图像的过程,它主要调用imread()和imshow()函数实现。OpenCV读取图像调用imread()函数,它将从指定的文件加载图像并返回矩阵,如果无法读取图像(因为缺少文件、权限不正确、格式不支持或图像无效等),则返回空矩阵(Mat::data==NULL)。OpenCV中显示图像调用imshow()函数,它将在指定窗口中显示一幅图像,窗口自动调整为图像大小。同时,在显示图像过程中,通常还会调用两个操作窗口的函数,它们分别是waitKey()和destroyAllWindows()。

下面是第一个示例程序,主要用于读取和加载经典的“Lena”图像。

# -*- coding:utf-8 -*-
# By: Eastmount CSDN 2021-01-26
import cv2

#读取图片
img = cv2.imread("Lena.png")

#显示图像
cv2.imshow("Demo", img)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果如图所示:

在这里插入图片描述


2.OpenCV读取修改像素

OpenCV中读取图像的像素值可以直接通过遍历图像的位置实现,如果是灰度图像则返回其灰度值,如果是彩色图像则返回蓝色(B)、绿色(G)、红色(G)三个分量值。其示例如下:

  • 灰度图像:返回值 = 图像[位置参数]
    如:test=img[88,42]

  • 彩色图像:返回值 = 图像[位置元素, 0 | 1 | 2 ]获取BGR三个通道像素
    如:blue=img[88,142,0] green=img[88,142,1] red=img[88,142,2]

当需要修改图像中的像素时,则定位指定像素并直接赋新像素值即可,彩色图像需要依次给三个分量赋值。如下代码所示。

# -*- coding:utf-8 -*-
# By: Eastmount CSDN 2021-01-26
import cv2

#读取图片
img = cv2.imread("Lena.png")

#读取像素
test = img[88,142]
print("读取的像素值:", test)

#修改像素
img[88,142] = [255, 255, 255]
print("修改后的像素值:", test)

#分别获取BGR通道像素
blue = img[88,142,0]
print("蓝色分量", blue)
green = img[88,142,1]
print("绿色分量", green)
red = img[88,142,2]
print("红色分量", red)

#显示图像
cv2.imshow("Demo", img)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

读取的像素值及修改后的像素值结果如图所示。

在这里插入图片描述

下面代码是将100到200行、150到250列的像素区域设置为白色的效果。

# -*- coding:utf-8 -*-
# By: Eastmount CSDN 2021-01-26
import cv2

#读取图片
img = cv2.imread("Lena.png")

#该区域设置为白色
img[100:200, 150:250] = [255,255,255]

#显示图像
cv2.imshow("Demo", img)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

下图是最终显示的效果图,它将img[100:200, 150:250] 区域显示为白色。

在这里插入图片描述

前面是直接读取和修改图像像素的方法,下面讲解通过Numpy库读取像素和修改像素的方法。读取像素调用item()函数实现,修改像素调用itemset()实现,其原型如下所示。

使用Numpy进行像素读取,调用方式如下:

  • 返回值 = 图像.item(位置参数)
    例如:blue = img.item(78, 100, 0)

使用Numpy的itemset函数修改像素,调用方式如下:

  • 图像.itemset(位置, 新值)
    例如:img.itemset((88,99), 255)

实现代码如下所示。

# -*- coding:utf-8 -*-
# By: Eastmount CSDN 2021-01-26
import cv2
import numpy

#读取图片
img = cv2.imread("Lena.png")
print(type(img))

#Numpy读取像素
print(img.item(78, 100, 0))
print(img.item(78, 100, 1))
print(img.item(78, 100, 2))

#Numpy修改像素
img.itemset((78, 100, 0), 100)
img.itemset((78, 100, 1), 100)
img.itemset((78, 100, 2), 100)
print(img.item(78, 100, 0))
print(img.item(78, 100, 1))
print(img.item(78, 100, 2))

输出结果如图所示,原始图像BGR像素值为88、84、196,修改后的像素值为100、100、100。

在这里插入图片描述


3.创建复制保存图像

由于在OpenCV2中没有CreateImage函数,如果需要创建图像,则需要使用Numpy库函数实现。如下述代码,调用np.zeros()函数创建空图像,创建的新图像使用Numpy数组的属性来表示图像的尺寸和通道信息,其中参数img.shape表示原始图像的形状,np.uint8表示类型。

  • emptyImage = np.zeros(img.shape, np.uint8)

例如img.shape为(500, 300, 3),它表示500×300像素的图像,3表示这是一个RGB图像。同时,可以复制原有图像来获取一幅新图像,调用copy()函数。

  • emptyImage2 = img.copy()

下列代码实现了图像的创建和复制功能。

# -*- coding:utf-8 -*-
# By: Eastmount CSDN 2021-01-26
import cv2
import numpy as np

#读取图片
img = cv2.imread("Lena.png")

#创建空图像
emptyImage = np.zeros(img.shape, np.uint8)

#复制图像
emptyImage2 = img.copy()

#显示图像
cv2.imshow("Demo1", img)
cv2.imshow("Demo2", emptyImage)
cv2.imshow("Demo3", emptyImage2)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

最终输出结果如图所示,Demo1表示原始图像,Demo2表示创建的空白图像,Demo3表示复制的图像。

在这里插入图片描述

在OpenCV中,输出图像到文件使用的函数为imwrite(),其函数原型如下:

  • retval = imwrite(filename, img[, params])
    – filename表示要保存的路径及文件名
    – img表示图像矩阵
    – params表示特定格式保存的参数编码,默认值为空。
    – 对于JPEG图片,params参数(cv2.IMWRITE_JPEG_QUALITY)表示图像的质量,用0-100的整数表示,默认值为95。
    – 对于PNG图片,该参数(cv2.IMWRITE_PNG_COMPRESSION)表示的是压缩级别,从0到9,压缩级别越高,图像尺寸越小,默认级别为3。
    – 对于PPM、PGM、PBM图片,该参数表示一个二进制格式的标志(cv2.IMWRITE_PXM_BINARY)。注意,该类型为Long,必须转换成int。

下面是一个调用imwrite()函数输出图像到指定的文件的代码。

# -*- coding:utf-8 -*-
# By: Eastmount CSDN 2021-01-26
import cv2
import numpy as np

#读取图像
img = cv2.imread("Lena.png")

#显示图像
cv2.imshow("Demo", img)

#保存图像
cv2.imwrite("dst1.jpg", img, [int(cv2.IMWRITE_JPEG_QUALITY), 5])  
cv2.imwrite("dst2.jpg", img, [int(cv2.IMWRITE_JPEG_QUALITY), 100])  
cv2.imwrite("dst3.png", img, [int(cv2.IMWRITE_PNG_COMPRESSION), 0])  
cv2.imwrite("dst4.png", img, [int(cv2.IMWRITE_PNG_COMPRESSION), 9])

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

原始图像“Lena.jpg”为222KB,调用imwrite()函数输出保存的图像共四张,如图所示,其中“dst1.jpg”被压缩,大小为4.90KB,“dst2.jpg”图像大小为99.1KB,“dst3.png”大小为499KB,“dst4.png”大小为193KB。

在这里插入图片描述


二.获取图像属性及通道

本小节将详细讲解获取图像属性、图像通道处理及图像遍历三个知识点。

1.图像属性

图像最常见的属性包括三个:图像形状(shape)、像素大小(size)和图像类型(dtype)。

(1)shape
通过shape关键字获取图像的形状,返回包含行数、列数、通道数的元组。其中灰度图像返回行数和列数,彩色图像返回行数、列数和通道数。

# -*- coding:utf-8 -*-
import cv2
import numpy

#读取图片
img = cv2.imread("Lena.png")

#获取图像形状
print(img.shape)

#显示图像
cv2.imshow("Demo", img)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

最终输出结果如图所示,(413L,412L,3L),它表示该图像共413行、412列像素,包括3个通道。

在这里插入图片描述

(2)size
通过size关键字获取图像的像素数目,其中灰度图像返回行数×列数,彩色图像返回行数×列数×通道数。下述代码就是获取“Lena.jpg”图像的大小。

# -*- coding:utf-8 -*-
import cv2
import numpy

#读取图片
img = cv2.imread("Lena.png")

#获取图像形状
print(img.shape)

#获取像素数目
print(img.size)

输出结果如图所示,包含510468个像素,即为413×412×3。

在这里插入图片描述

(3)dtype
通过dtype关键字获取图像的数据类型,通常返回uint8。

# -*- coding:utf-8 -*-
import cv2
import numpy

#读取图片
img = cv2.imread("Lena.png")

#获取图像形状
print(img.shape)

#获取像素数目
print(img.size)

#获取图像数据类型
print(img.dtype)

输出结果如下所示:

(413L, 412L, 3L)
510468
uint8

2.图像通道处理

OpenCV通过split()函数和merge()函数实现对图像通道的处理,包括通道分离和通道合并。

(1)split()函数
OpenCV读取的彩色图像由蓝色(B)、绿色(G)、红色(R)三原色组成,每一种颜色可以认为是一个通道分量,如图所示。

在这里插入图片描述

split()函数用于将一个多通道数组分量成三个单通道,其函数原型如下所示:

  • mv = split(m[, mv])
    – m表示输入的多通道数组
    – mv表示输出的数组或vector容器

下面的代码是获取彩色“Lena”图像三个颜色通道并分别显示。

# -*- coding:utf-8 -*-
# By: Eastmount CSDN 2021-01-26
import cv2
import numpy

#读取图片
img = cv2.imread("Lena.png")

#拆分通道
b, g, r = cv2.split(img)

#b = img[:, :, 0]
#g = img[:, :, 1]
#r = img[:, :, 2]

#显示原始图像
cv2.imshow("B", b)
cv2.imshow("G", g)
cv2.imshow("R", r)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

显示结果如图所示,它展示了B、G、R三个通道的颜色分量。也可以获取不同通道颜色,核心代码为:

  • b = cv2.split(a)[0]
  • g = cv2.split(a)[1]
  • r = cv2.split(a)[2]

在这里插入图片描述

(2)merge()函数
该函数是split()函数的逆向操作,将多个数组合成一个通道的数组,从而实现图像通道的合并,其函数原型如下:
dst = merge(mv[, dst])
– mv表示输入的需要合并的数组,所有矩阵必须有相同的大小和深度
– dst表示输出的具有与mv[0]相同大小和深度的数组

下列代码实现了图像三个颜色通道的合。

# -*- coding:utf-8 -*-
# By: Eastmount CSDN 2021-01-26
import cv2
import numpy as np

#读取图片
img = cv2.imread("Lena.png")

#拆分通道
b, g, r = cv2.split(img)

#合并通道
m = cv2.merge([b, g, r])
cv2.imshow("Merge", m)
           
#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

显示结果如图所示,它将拆分的B、G、R三个通道的颜色分量进行了合并,接着显示合并后的图像。

在这里插入图片描述

同时,可以调用该函数提取图像的不同颜色,比如提取B颜色通道,G、B通道设置为0。代码如下所示:

# -*- coding:utf-8 -*-
# By: Eastmount CSDN 2021-01-26
import cv2
import numpy as np

#读取图片
img = cv2.imread("Lena.png")
rows, cols, chn = img.shape

#拆分通道
b = cv2.split(img)[0]

#设置g、r通道为0
g = np.zeros((rows,cols), dtype=img.dtype)
r = np.zeros((rows,cols), dtype=img.dtype)

#合并通道
m = cv2.merge([b, g, r])
cv2.imshow("Merge", m)
           
#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

此时显示的图像为蓝色通道,如图所示,其他颜色的通道方法也类似。

在这里插入图片描述


三.图像算数与逻辑运算

本小节主要讲解图像的算法运算与逻辑运算,包括图像加法、图像减法、图像与运算、图像或运算、图像异或运算与图像非运算。

1.图像加法运算

图像加法运算主要有两种方法。第一种是调用Numpy库实现,目标图像像素为两张图像的像素之和;第二种是通过OpenCV调用add()函数实现。本小节主要讲解第二种方法,其函数原型如下:

  • dst = add(src1, src2[, dst[, mask[, dtype]]])
    – src1表示第一张图像的像素矩阵
    – src2表示第二张图像的像素矩阵
    – dst表示输出的图像,必须和输入图像具有相同的大小和通道数
    – mask表示可选操作掩码(8位单通道数组),用于指定要更改的输出数组的元素。
    – dtype表示输出数组的可选深度

注意,当两幅图像的像素值相加结果小于等于255时,则输出图像直接赋值该结果,如120+48赋值为168;如果相加值大于255,则输出图像的像素结果设置为255,如(255+64) 赋值为255。下面的代码实现了图像加法运算。

#coding:utf-8
import cv2  
import numpy as np  
 
#读取图片
img = cv2.imread("Lena.png")

#图像各像素加100
m = np.ones(img.shape, dtype="uint8")*100

#OpenCV加法运算
result = cv2.add(img, m)

#显示图像
cv2.imshow("original", img)
cv2.imshow("result", result)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出如图所示,左边为原始图像,右边为像素值增加100像素后的图像,输出图像显示更偏白。

在这里插入图片描述


2.图像减法运算

图像减法运算主要调用subtract()函数实现,其原型如下所示:

  • dst = subtract(src1, src2[, dst[, mask[, dtype]]])
    – src1表示第一张图像的像素矩阵
    – src2表示第二张图像的像素矩阵
    – dst表示输出的图像,必须和输入图像具有相同的大小和通道数
    – mask表示可选操作掩码(8位单通道数组),用于指定要更改的输出数组的元素。
    – dtype表示输出数组的可选深度

实现代码详见如下:

#coding:utf-8
# By: Eastmount CSDN 2021-01-26
import cv2  
import numpy as np  
 
#读取图片 
img = cv2.imread("Lena.png")

#图像各像素减50
m = np.ones(img.shape, dtype="uint8")*50

#OpenCV减法运算
result = cv2.subtract(img, m)

#显示图像
cv2.imshow("original", img)
cv2.imshow("result", result)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出如图所示,左边为原始图像,右边为像素值减少50像素后的图像,输出图像显示更偏暗。

在这里插入图片描述


3.图像与运算

与运算是计算机中一种基本的逻辑运算方式,符号表示为“&”,其运算规则为:0&0=0、0&1=0、1&0=0、1&1=1。图像的与运算是指两张图像(灰度图像或彩色图像均可)的每个像素值进行二进制“与”操作,实现图像裁剪。

  • dst = bitwise_and(src1, src2[, dst[, mask]])
    – src1表示第一张图像的像素矩阵
    – src2表示第二张图像的像素矩阵
    – dst表示输出的图像,必须和输入图像具有相同的大小和通道数
    – mask表示可选操作掩码(8位单通道数组),用于指定要更改的输出数组的元素。

下面代码是通过图像与运算实现图像剪裁的功能。

#coding:utf-8
# By: Eastmount CSDN 2021-01-26
import cv2  
import numpy as np  
 
#读取图片 
img = cv2.imread("Lena.png", cv2.IMREAD_GRAYSCALE)

#获取图像宽和高
rows, cols = img.shape[:2]
print(rows, cols)

#画圆形
circle = np.zeros((rows, cols), dtype="uint8")
cv2.circle(circle, (int(rows/2.0), int(cols/2)), 80, 255, -1)
print(circle.shape)
print(img.size, circle.size)

#OpenCV图像与运算
result = cv2.bitwise_and(img, circle)

#显示图像
cv2.imshow("original", img)
cv2.imshow("circle", circle)
cv2.imshow("result", result)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出如图所示,原始图像与圆形进行与运算之后,提取了其中心轮廓。同时输出图像的形状为256×256,图像大小为65536个像素。注意,两张进行与运算的图像大小和类型必须一致。

在这里插入图片描述


4.图像或运算

逻辑或运算是指如果一个操作数或多个操作数为 true,则逻辑或运算符返回布尔值 true;只有全部操作数为false,结果才是 false。图像的或运算是指两张图像(灰度图像或彩色图像均可)的每个像素值进行二进制“或”操作,实现图像裁剪。其函数原型如下所示:

  • dst = bitwise_or(src1, src2[, dst[, mask]])
    – src1表示第一张图像的像素矩阵
    – src2表示第二张图像的像素矩阵
    – dst表示输出的图像,必须和输入图像具有相同的大小和通道数
    – mask表示可选操作掩码(8位单通道数组),用于指定要更改的输出数组的元素。

下面代码是通过图像或运算实现图像剪裁的功能。

#coding:utf-8
# By: Eastmount CSDN 2021-01-26
import cv2  
import numpy as np  
 
#读取图片 
img = cv2.imread("Lena.png", cv2.IMREAD_GRAYSCALE)

#获取图像宽和高
rows, cols = img.shape[:2]
print(rows, cols)

#画圆形
circle = np.zeros((rows, cols), dtype="uint8")
cv2.circle(circle, (int(rows/2), int(cols/2)), 80, 255, -1)
print(circle.shape)
print(img.size, circle.size)

#OpenCV图像或运算
result = cv2.bitwise_or(img, circle)

#显示图像
cv2.imshow("original", img)
cv2.imshow("circle", circle)
cv2.imshow("result", result)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出如图所示,原始图像与圆形进行或运算之后,提取了图像除中心原形之外的像素值。

在这里插入图片描述


5.图像异或运算

逻辑异或运算(xor)是一个数学运算符,数学符号为“⊕”,计算机符号为“xor”,其运算法则为:如果a、b两个值不相同,则异或结果为1;如果a、b两个值相同,异或结果为0。图像的异或运算是指两张图像(灰度图像或彩色图像均可)的每个像素值进行二进制“异或”操作,实现图像裁剪。其函数原型如下所示:

  • dst = bitwise_xor(src1, src2[, dst[, mask]])
    – src1表示第一张图像的像素矩阵
    – src2表示第二张图像的像素矩阵
    – dst表示输出的图像,必须和输入图像具有相同的大小和通道数
    – mask表示可选操作掩码(8位单通道数组),用于指定要更改的输出数组的元素。

图像异或运算的实现代码如下所示。

#coding:utf-8
# By: Eastmount CSDN 2021-01-26
import cv2  
import numpy as np  
 
#读取图片 
img = cv2.imread("Lena.png", cv2.IMREAD_GRAYSCALE)

#获取图像宽和高
rows, cols = img.shape[:2]
print(rows, cols)

#画圆形
circle = np.zeros((rows, cols), dtype="uint8")
cv2.circle(circle, (int(rows/2), int(cols/2)), 80, 255, -1)
print(circle.shape)
print(img.size, circle.size)

#OpenCV图像异或运算
result = cv2.bitwise_xor(img, circle)

#显示图像
cv2.imshow("original", img)
cv2.imshow("circle", circle)
cv2.imshow("result", result)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

原始图像与圆形进行异或运算之后输出如图所示。

在这里插入图片描述


6.图像非运算

图像非运算就是图像的像素反色处理,它将原始图像的黑色像素点转换为白色像素点,白色像素点则转换为黑色像素点,其函数原型如下:

  • dst = bitwise_not(src1, src2[, dst[, mask]])
    – src1表示第一张图像的像素矩阵
    – src2表示第二张图像的像素矩阵
    – dst表示输出的图像,必须和输入图像具有相同的大小和通道数
    – mask表示可选操作掩码(8位单通道数组),用于指定要更改的输出数组的元素。

图像非运算的实现代码如下所示。

#coding:utf-8
import cv2  
import numpy as np  
 
#读取图片 
img = cv2.imread("Lena.png", cv2.IMREAD_GRAYSCALE)

#OpenCV图像非运算
result = cv2.bitwise_not(img)

#显示图像
cv2.imshow("original", img)
cv2.imshow("result", result)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

原始图像非运算之后输出如图所示。

在这里插入图片描述


四.图像融合处理

图像融合通常是指将2张或2张以上的图像信息融合到1张图像上,融合的图像含有更多的信息,能够更方便人们观察或计算机处理。如图所示,它将两张不清晰的图像融合得到更清晰的图。

在这里插入图片描述

图像融合是在图像加法的基础上增加了系数和亮度调节量,它与图像的主要区别如下:

  • 图像加法:目标图像 = 图像1 + 图像2
  • 图像融合:目标图像 = 图像1 × 系数1 + 图像2 × 系数2 + 亮度调节量

在OpenCV中,图像融合主要调用addWeighted()函数实现,其原型如下。需要注意的是,两张融合图像的像素大小必须一致,参数gamma不能省略。

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

下面的代码是将两张图片进行图像融合,两张图片的系数均为1。

#encoding:utf-8
# By: Eastmount CSDN 2021-01-26
import cv2  
import numpy as np  
import matplotlib.pyplot as plt
 
#读取图片
src1 = cv2.imread('lena-hd.png')
src2 = cv2.imread('na.png')

#图像融合
result = cv2.addWeighted(src1, 1, src2, 1, 0)

#显示图像
cv2.imshow("src1", src1)
cv2.imshow("src2", src2)
cv2.imshow("result", result)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果如图所示,它将src1图像和src2图像按比例系数进行了融合,生成目标结果图result。

在这里插入图片描述

同样可以设置不同的融合比例,比如函数设为cv2.addWeighted(src1, 0.6, src2, 0.8, 10),则输出的结果如图所示。

在这里插入图片描述


五.获取图像ROI区域

ROI(Region of Interest)表示感兴趣区域,是指从被处理图像以方框、圆形、椭圆、不规则多边形等方式勾勒出需要处理的区域。可以通过各种算子(Operator)和函数求得感兴趣ROI区域,被广泛应用于热点地图、人脸识别、图像分割等领域。如图获取Lena图的脸部轮廓。

在这里插入图片描述

通过像素矩阵可以直接获取ROI区域,如img[200:400, 200:400]。下面的代码是获取脸部ROI区域并显示。

# -*- coding:utf-8 -*-
import cv2
import numpy as np

#读取图片
img = cv2.imread("Lena.png")

#定义200×200矩阵 3对应BGR
face = np.ones((200, 200, 3))

#显示原始图像
cv2.imshow("Demo", img)

#显示ROI区域
face = img[150:350, 150:350]
cv2.imshow("face", face)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果如图所示,它将Lena原图的脸部提取出来。

在这里插入图片描述

同样,如果想将提取的ROI区域融合至其他图片,则使用赋值语句即可。下面代码是将提取的Lena头部轮廓融合至一幅新的图像中。

# -*- coding:utf-8 -*-
# By: Eastmount CSDN 2021-01-26
import cv2
import numpy as np

#读取图片
img = cv2.imread("Lena.png")
test = cv2.imread("test.jpg")

#定义150×150矩阵 3对应BGR
face = np.ones((150, 150, 3))

#显示ROI区域
face = img[170:320, 170:320]
cv2.imshow("Demo", face)

test[220:370, 220:370] = face
cv2.imshow("Result", test)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

运行结果如图所示,它将提取的150×150脸部轮廓融合至新的图像 [220:370, 220:370] 区域。

在这里插入图片描述


六.图像类型转换

在日常生活中,我们看到的大多数彩色图像都是RGB类型,但是在图像处理过程中,常常需要用到灰度图像、二值图像、HSV、HSI等颜色。图像类型转换是指将一种类型转换为另一种类型,比如彩色图像转换为灰度图像、BGR图像转换为RGB图像。OpenCV提供了200多种不同类型之间的转换,其中最常用的包括3类,如下:

  • cv2.COLOR_BGR2GRAY
  • cv2.COLOR_BGR2RGB
  • cv2.COLOR_GRAY2BGR

OpenCV提供了cvtColor()函数实现这些功能。其函数原型如下所示:

  • dst = cv2.cvtColor(src, code[, dst[, dstCn]])
    – src表示输入图像,需要进行颜色空间变换的原图像
    – dst表示输出图像,其大小和深度与src一致
    – code表示转换的代码或标识
    – dstCn表示目标图像通道数,其值为0时,则有src和code决定

该函数的作用是将一个图像从一个颜色空间转换到另一个颜色空间,其中,RGB是指Red、Green和Blue,一副图像由这三个通道(channel)构成;Gray表示只有灰度值一个通道;HSV包含Hue(色调)、Saturation(饱和度)和Value(亮度)三个通道。在OpenCV中,常见的颜色空间转换标识包括CV_BGR2BGRA、CV_RGB2GRAY、CV_GRAY2RGB、CV_BGR2HSV、CV_BGR2XYZ、CV_BGR2HLS等。

下面是调用cvtColor()函数将图像进行灰度化处理的代码。

#encoding:utf-8
import cv2  
import numpy as np  
import matplotlib.pyplot as plt
 
#读取图片
src = cv2.imread('Lena.png')

#图像类型转换
result = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)

#显示图像
cv2.imshow("src", src)
cv2.imshow("result", result)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果如图所示,它将左边的彩色图像转换为右边的灰度图像,更多灰度转化的算法参考第15和16篇文章。

在这里插入图片描述

同样,可以调用 grayImage = cv2.cvtColor(src, cv2.COLOR_BGR2HSV) 核心代码将彩色图像转换为HSV颜色空间,如图所示。

在这里插入图片描述

下面代码对比了九种常见的颜色空间,包括BGR、RGB、GRAY、HSV、YCrCb、HLS、XYZ、LAB和YUV,并循环显示处理后的图像。

# -*- coding: utf-8 -*-
# By: Eastmount CSDN 2021-01-26
import cv2  
import numpy as np  
import matplotlib.pyplot as plt

#读取原始图像
img_BGR = cv2.imread('na.png')

#BGR转换为RGB
img_RGB = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2RGB)

#灰度化处理
img_GRAY = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2GRAY)

#BGR转HSV
img_HSV = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2HSV)

#BGR转YCrCb
img_YCrCb = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2YCrCb)

#BGR转HLS
img_HLS = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2HLS)

#BGR转XYZ
img_XYZ = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2XYZ)

#BGR转LAB
img_LAB = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2LAB)

#BGR转YUV
img_YUV = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2YUV)

#调用matplotlib显示处理结果
titles = ['BGR', 'RGB', 'GRAY', 'HSV', 'YCrCb', 'HLS', 'XYZ', 'LAB', 'YUV']  
images = [img_BGR, img_RGB, img_GRAY, img_HSV, img_YCrCb,
          img_HLS, img_XYZ, img_LAB, img_YUV]  
for i in range(9):  
   plt.subplot(3, 3, i+1), plt.imshow(images[i], 'gray')  
   plt.title(titles[i])  
   plt.xticks([]),plt.yticks([])  
plt.show()

其运行结果如图所示:

在这里插入图片描述


七.总结

本文主要讲解Python和OpenCV的图像基础处理,从读取显示图像到读取修改像素,从创建、复制、保存图像到获取图像属性合通道,再详细讲解了图像算数与逻辑运算,包括图像加法、减法、与运算、或运算、异或运算、非运算,最后讲解了图像融合和获取图像ROI区域及图像类型转换。本章知识为后续的图像处理、图像识别、图像变换打下扎实基础。

时光嘀嗒嘀嗒的流失,这是我在CSDN写下的第八篇年终总结,比以往时候来的更早一些。《敏而多思,宁静致远》,仅以此篇纪念这风雨兼程的一年,这感恩的一年。列车上只写了一半,这两天完成,思远,思君O(∩_∩)O

在这里插入图片描述

2020年8月18新开的“娜璋AI安全之家”,主要围绕Python大数据分析、网络空间安全、人工智能、Web渗透及攻防技术进行讲解,同时分享CCF、SCI、南核北核论文的算法实现。娜璋之家会更加系统,并重构作者的所有文章,从零讲解Python和安全,写了近十年文章,真心想把自己所学所感所做分享出来,还请各位多多指教,真诚邀请您的关注!谢谢。

在这里插入图片描述

(By:Eastmount 2021-01-26 晚上10点 http://blog.csdn.net/eastmount/ )


参考文献,在此感谢这些大佬,共勉!

  • [1]冈萨雷斯. 数字图像处理(第3版)[M]. 北京:电子工业出版社, 2013.
  • [2]毛星云, 冷雪飞. OpenCV3编程入门[M]. 北京:电子工业出版社, 2015.
  • [3]Eastmount. [Python图像处理] 一.图像处理基础知识及OpenCV入门函数[EB/OL]. (2018-08-16). https://blog.csdn.net/Eastmount/article/details/81748802.
  • [4]Eastmount. [Python图像处理] 二.OpenCV+Numpy库读取与修改像素[EB/OL]. (2018-08-28). https://blog.csdn.net/eastmount/article/details/82120114.
  • [5]zangyu. OpenCV Python教程(1、图像的载入、显示和保存) [EB/OL]. (2016-08-24). https://www.cnblogs.com/zangyu/p/5802142.html.
  • [6]Jumping boy. python+OpenCV图像处理(一)读取、复制、显示、保存[EB/OL]. (2018-05-25). https://blog.csdn.net/qq_40962368/article/details/80444144.
  • [7]Eastmount. [Python图像处理] 五.图像融合、加法运算及图像类型转换[EB/OL]. (2018-09-03). https://blog.csdn.net/Eastmount/article/details/82347501.
  • [8]jnulzl. openCV—Python(6)—— 图像算数与逻辑运算[EB/OL]. (2015-07-29). https://blog.csdn.net/jnulzl/article/details/47129887.
  • [9]tengfei461807914. python opencv入门 图像上的算术运算(7)[EB/OL]. (2017-07-20). https://blog.csdn.net/tengfei461807914/article/details/75514689.
  • [10]Eastmount. [Python图像处理] 三.获取图像属性、兴趣ROI区域及通道处理[EB/OL]. (2018-08-29). https://blog.csdn.net/Eastmount/article/details/82177300.

猜你喜欢

转载自blog.csdn.net/Eastmount/article/details/113192978