图像特效
图像融合
图像融合,即按照一定的比例将两张图片融合在一起!例如下面图一图二经过融合之后形成图三!
执行这样的融合需要用到opencv提供的如下api
| cv.addWeighted(图像1,权重1,图像2,权重2,叠加之后的像素偏移值)
注意:
进行叠加的两张图片宽高应该相同
叠加之后的像素偏移值如果填的话不要填太大,超过255会导致图像偏白
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | import cv2 as cv
itheima = cv.imread("img/itheima.jpg", cv.IMREAD_COLOR)
cv.imshow("itheima",itheima)
tony = cv.imread("img/tony.jpg", cv.IMREAD_COLOR)
cv.imshow("tony",tony)
# 进行叠加时的插值
dst = cv.addWeighted(itheima,0.5,tony,0.5,0)
cv.imshow("dst",dst)
cv.waitKey(0)
cv.destroyAllWindows()
|
灰度处理
一张彩色图片通常是由BGR三个通道叠加而成,为了便于图像特征识别,我们通常会将一张彩色图片转成灰度图片来进行分析,当我们转成灰色图片之后,图片中边缘,轮廓特征仍然是能够清晰看到的,况且在这种情况下我们仅需要对单一通道进行分析,会简化很多操作!
示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | import cv2 as cv
# 方式一 : 直接以灰度图像的形式读取
# img = cv.imread("img/itheima.jpg", cv.IMREAD_GRAYSCALE)
# cv.imshow("dstImg",img)
# cv.waitKey(0)
# 方式二: 以彩图的方式读取
img = cv.imread("img/itheima.jpg",cv.IMREAD_COLOR)
# 将原图的所有颜色转成灰色
dstImg = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.imshow("dstImg",dstImg)
cv.waitKey(0)
|
原理演示
方式一: gray = (B+G+R)/3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | img = cv.imread("img/itheima.jpg",cv.IMREAD_COLOR)
# 获取图片宽高信息
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 定义一个与原图同样大小的矩阵
dstImg = np.zeros(imgInfo,np.uint8)
# 遍历dstImg,填充数据
for row in range(height):
for col in range(width):
# 获取原来的像素值
(b,g,r) = img[row,col]
# 计算灰度
gray = np.uint8((int(b)+int(g)+int(r))/3)
print(gray)
# 向目标矩阵中填值
dstImg[row,col]=gray
cv.imshow("dstimg",dstImg)
cv.waitKey(0)
|
方式二: 利用著名的彩色转灰色心理学公式: Gray = R*0.299 + G*0.587 + B*0.114
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | import cv2 as cv
import numpy as np
# 将图片数据读取进来
img = cv.imread("img/itheima.jpg",cv.IMREAD_COLOR)
# 获取图片宽高信息
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 定义一个与原图同样大小的矩阵
dstImg = np.zeros(imgInfo,np.uint8)
# 遍历dstImg,填充数据
for row in range(height):
for col in range(width):
# 获取原来的像素值
(b,g,r) = img[row,col]
# 计算灰度
# gray = np.uint8((int(b)+int(g)+int(r))/3)
# 采用心理学公式计算
gray = b*0.114 + g*0.587 + r*0.299
# 向目标矩阵中填值
dstImg[row,col]=gray
cv.imshow("dstimg",dstImg)
cv.waitKey(0)
|
颜色反转
灰图反转
例如在一张灰度图片中,某个像素点的灰度值为100, 然后我们进行颜色反转之后,灰度值变为255-100 = 155 , 从下图我们可以看出,进行颜色反转之后,整张图片看起来非常像我们小时候所看到的胶卷底片!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 | import cv2 as cv
import numpy as np
# 将图片数据读取进来
img = cv.imread("img/itheima.jpg",cv.IMREAD_GRAYSCALE)
cv.imshow("img",img)
# 获取原图信息
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 创建一个和原图同样大小的矩阵
dstImg = np.zeros((height,width,1),np.uint8)
for row in range(height):
for col in range(width):
# 获取原图中的灰度值
gray = img[row,col]
# 反转
newColor = 255 - gray
# 填充
dstImg[row,col]=newColor
cv.imshow("dstimg",dstImg)
cv.waitKey(0)
|
彩图反转
学会了前面灰度图片的反转,下面我们进一步来学习彩色图片的反转. 相对于灰度图片,彩色图片其实只是由3个灰度图片叠加而成,如果让彩色图片进行颜色反转,我们其实只需要让每个通道的灰度值进行反转即可!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | import cv2 as cv
import numpy as np
# 将图片数据读取进来
img = cv.imread("img/itheima.jpg",cv.IMREAD_COLOR)
cv.imshow("img",img)
# 获取原图信息
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 创建一个和原图同样大小的矩阵
dstImg = np.zeros((height,width,3),np.uint8)
for row in range(height):
for col in range(width):
# 获取原图中的灰度值
(b,g,r) = img[row,col]
# 反转
new_b = 255-b
new_g = 255-g
new_r = 255-r
# 填充
dstImg[row,col]=(new_b,new_g,new_r)
cv.imshow("dstimg",dstImg)
cv.waitKey(0)
|
马赛克效果
马赛克指现行广为使用的一种图像(视频)处理手段,此手段将影像特定区域的色阶细节劣化并造成色块打乱的效果,因为这种模糊看上去有一个个的小格子组成,便形象的称这种画面为马赛克。其目的通常是使之无法辨认。
下面,我们来介绍一下实现马赛克的思路!
假设我们将要打马赛克的区域按照4x4进行划分,我们就会得到如下左图的样子!
接下来我们要干的就是让这个4x4块内的所有像素点的颜色值都和第一个像素点的值一样.
经过运算之后,我们整个4x4块内的所有像素点就都成了黄色! 从而掩盖掉了原来的像素内容!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 | import cv2 as cv
import numpy as np
# 将图片数据读取进来
img = cv.imread("img/itheima.jpg",cv.IMREAD_COLOR)
cv.imshow("img",img)
# 获取原图信息
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 遍历要打马赛克的区域 宽度430 高度220
for row in range(160,240):
for col in range(380,670):
# 每10×10的区域将像素点颜色改成一致
if row%10==0 and col%10==0:
# 获取当前颜色值
(b,g,r) = img[row,col]
# 将10×10区域内的颜色值改成一致
for i in range(10):
for j in range(10):
img[row+i,col+j]= (b,g,r)
# 显示效果图
cv.imshow('dstimg',img)
cv.waitKey(0)
|
毛玻璃效果
毛玻璃的效果和我们前面讲过的马赛克效果其实是非常相似的, 只不过毛玻璃效果是从附近的颜色块中,随机的去选择一个颜色值作为当前像素点的值!
我们还是以4x4的块大小为例,当我们去遍历每个像素点的时候, 当前像素点的颜色值,我们随机从它附近4x4的区域内选择一个颜色值作为当前像素点的值!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 | import cv2 as cv
import numpy as np
import random
# 将图片数据读取进来
img = cv.imread("img/itheima.jpg",cv.IMREAD_COLOR)
cv.imshow("img",img)
# 获取原图信息
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 创建一个和原图同样大小的空白矩阵
dstImg = np.zeros((height,width,3),np.uint8)
# 定义偏移量,表示从后面6个像素中随机选取一个颜色值
offset=6
# 向空白矩阵中填入颜色值
for row in range(height):
for col in range(width):
# 计算随机数
index = int(random.random()*offset)
# 计算随机行号
randomRow = row + index if row+index<height else height-1
# 计算随机列号
randomCol = col + index if col+index<width else width-1
# 选择附近的一个像素点颜色
(b,g,r) = img[randomRow,randomCol]
# 填充到空白矩阵中
dstImg[row,col]=(b,g,r)
# 显示效果图
cv.imshow('dstimg',dstImg)
cv.waitKey(0)
|
图片浮雕效果
梯度
前面我们做过一个毛玻璃效果的图片, 其实原理很简单对吧,我们只需要让当前像素点的颜色和附近像素点的颜色一致就可以了! 这样带来的效果其实是图片变得模糊.
那么模糊图片和清晰图片之间的差异是什么呢? 从视觉角度来讲, 图像模糊是因为图像中物体的边缘轮廓不明显,就好比一个近视的同学,摘下眼镜看东西,整个世界的轮廓都是模糊的. 再进一步理解就是物体边缘灰度变化不强烈,层次感不强造成的! 那么反过来, 如果物体轮廓边缘灰度变化明显些, 层次感强些图像不就是清晰一些了吗?
这种灰度变化明不明显强不强烈该如何定义呢 ? 我们学过微积分, 微分就是求函数的变化率,即导数(梯度). 其实梯度我们可以把它理解为颜色变化的强度, 更直白一点说梯度相当于是2个相邻像素之间的差值!
我们先看第一行数据, 在X轴方向上,颜色值都为100,我们并没有看到任何的边缘
但是在Y轴方向上, 我们可以看到100和50之间有明显的边缘,其实这个就是梯度
浮雕效果相信大家都有比较熟悉,在opencv中我们想要实现浮雕效果,只需套用如下公式即可:
其中,相邻像素值之差可以体现边缘的突变或者称为梯度
末尾加上120只是为了增加像素值的灰度.
当然,在这个运算的过程中,我们还需要注意计算结果有可能小于0或者大于255
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 | import cv2 as cv
import numpy as np
import random
# 将图片数据读取进来
img = cv.imread("img/itheima.jpg",cv.IMREAD_COLOR)
cv.imshow("img",img)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 将图片转成灰度图片
grayImg = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 创建一张与原图相同大小的空白矩阵
dstImg = np.zeros((height,width,1),np.uint8)
# 向空白图片中填充内容
for row in range(height):
for col in range(width-1):
# 获取当前像素值
gray0 = grayImg[row,col]
# 获取相邻一个像素点灰度
gray1 = grayImg[row,col+1]
# 计算新的灰度值
gray = int(gray0)-int(gray1)+120
# 校验gray是否越界
gray = gray if gray<255 else 255
gray = gray if gray>0 else 0
# 将值填充到空白的矩阵中
dstImg[row,col] = gray
# 显示图片
cv.imshow("dstimg",dstImg)
cv.waitKey(0)
|
绘制图形
在这之前,我们学过的所有操作,其实都是在原图的基础上进行修改! 现在假设我们想在原图上绘制一些标记或者轮廓,那么我们就需要来学习一下opencv给我们提供的相应API,在这些API中,常见的有绘制直线,绘制圆,绘制矩形
| # 绘制线段 参数2:起始点 参数3:结束点 参数4:颜色 参数5:线条宽度
cv.line(图片矩阵,起始点,结束点,颜色值,线条的宽度,线条的类型)
# 绘制一个矩形 参数2: 左上角 参数3:右下角 参数4:颜色 参数5:线条宽度,若为负数,则填充整个矩形
cv.rectangle(dstImg,(250,90),(470,180),(0,255,0),-1)
# 绘制圆形 参数2:圆心 参数3:半径 参数4:颜色 参数5:线条宽度
cv.circle(dstImg,(450,280),90,(0,0,255),5)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 | import cv2 as cv
import numpy as np
import random
# 创建一个空白的矩阵
dstImg = np.zeros((400,600,3),np.uint8)
# 绘制线段 参数2:起始点 参数3:结束点 参数4:颜色 参数5:线条宽度
cv.line(dstImg,(50,10),(400,10),(255,255,0),10)
# 扛锯齿
cv.line(dstImg,(50,50),(400,50),(255,0,0),10,cv.LINE_AA)
# 绘制一个三角形
cv.line(dstImg,(50,350),(150,200),(255,0,0),10)
cv.line(dstImg,(150,200),(300,350),(0,255,0),10)
cv.line(dstImg,(300,350),(50,350),(0,0,255),10)
# 绘制一个矩形 参数2: 左上角 参数3:右下角 参数4:颜色 参数5:线条宽度,若为负数,则填充整个矩形
cv.rectangle(dstImg,(250,90),(470,180),(0,255,0),-1)
# 绘制圆形 参数2:圆心 参数3:半径 参数4:颜色 参数5:线条宽度
cv.circle(dstImg,(450,280),90,(0,0,255),5)
# 显示图片
cv.imshow("dstimg",dstImg)
cv.waitKey(0)
|
文字图片绘制
在图片上绘制文本,我们需要用到
| # 绘制文字
font = cv.FONT_HERSHEY_SIMPLEX
# 参数2:文本 参数3:显示位置 参数4:字体 参数5:大小 参数6:颜色 参数7:粗细 参数8:线条类型
cv.putText(img,'www.itheima.com',(395,138),font,1,(0,0,255),2,cv.LINE_AA)
|
示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 | # 将图片数据读取进来
img = cv.imread("img/itheima.jpg",cv.IMREAD_COLOR)
cv.imshow("img",img)
imgInfo = img.shape
height = imgInfo[0]
width = imgInfo[1]
# 在图片上绘制矩形
cv.rectangle(img,(380,150),(666,236),(0,255,0),5)
# 绘制图片
lenaImg = cv.imread("img/lena.jpg",cv.IMREAD_COLOR)
# 获取图片信息
imgInfo = lenaImg.shape
# 计算缩放图片宽高
scale = 0.3
height = int(imgInfo[0]*scale)
width = int(imgInfo[1]*scale)
# 缩放图片
newLenaImg = cv.resize(lenaImg,(height,width))
# 遍历
for row in range(height):
for col in range(width):
img[50+row,100+col]=newLenaImg[row,col]
cv.imshow('dstimg',img)
cv.waitKey(0)
|
注意: opencv不支持中文显示,若想显示中文,需要额外安装中文字体库