其他
干货 | OpenCV看这篇就够了,9段代码详解图像变换基本操作
以下文章来源于大数据 ,作者王天庆
作者 | 王天庆,长期从事分布式系统、数据科学与工程、人工智能等方面的研究与开发,在人脸识别方面有丰富的实践经验。现就职某世界100强企业的数据实验室,从事数据科学相关技术领域的预研工作。
来源 | 大数据(ID:hzdashuju)
01 OpenCV介绍
pip install opencv-python
conda install opencv
# 查看引入OpenCV库时是否报错
import cv2
# 查看安装的版本
cv2.__version__
# 我这里显示的版本信息是 '3.4.1'
代码清单① OpenCV中图片的读取和存储
import cv2
import numpy as np
# 使用imread()方法读入一个图片
image = cv2.imread("lena.jpg")
# 看一下数据的存储维度
image.shape
# 返回:(121, 121, 3)
# 将读入的数据image打印出来
print(image)
'''
如果读入数据失败,返回值将不是一个array类型,而是None
我们可以看到图片数据的存储形式:
[[[113 152 227]
[109 153 230]
[104 152 230]
...,
[ 58 93 166]
[119 156 212]
[149 182 232]]
[[107 149 224]
[103 149 226]
[ 97 149 225]
...,
[ 79 112 175]
[ 77 108 159]
[ 65 91 137]]
[[101 148 222]
[ 96 146 222]
[ 91 146 221]
...,
[ 56 80 132]
[ 3 22 65]
[ 0 3 40]]
...,
[[ 21 40 45]
[ 24 37 45]
[ 34 41 50]
...,
[ 20 34 57]
[ 7 24 50]
[ 8 27 54]]
[[ 17 35 36]
[ 20 32 38]
[ 22 29 38]
...,
[ 13 29 52]
[ 28 45 72]
[ 41 59 90]]
[[ 15 31 30]
[ 19 31 35]
[ 21 28 37]
...,
[ 13 29 52]
[ 48 64 93]
[ 71 90 123]]]
'''
# 将存储图片数据的image变量写到磁盘中,写出的文件名为lena.bak.jpg
# 其返回值结果为True代表写入成功,反之代表失败
cv2.imwrite("lena.bak.jpg",image)
could not find a writer for the specified extension in function cv::imwrite_
代码清单② 使用OpenCV将图片灰度化处理
import numpy as np
import cv2
img = cv2.imread("lena.jpg")
print(img.shape)
# (121, 121, 3)
# 使用cv2.cvtColor() 方法将彩色图片转换为灰度图片
gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
print(gray_img.shape)
# (121, 121)
# 将转换后的灰度图片回复成BGR形式
img2 = cv2.cvtColor(gray_img,cv2.COLOR_GRAY2BGR)
print(img2.shape)
# (121, 121, 3)
# 输出彩色图片img的内容
print(img)
'''
[[[113 152 227]
[109 153 230]
[104 152 230]
...,
[ 58 93 166]
[119 156 212]
[149 182 232]]
[[107 149 224]
[103 149 226]
[ 97 149 225]
...,
[ 79 112 175]
[ 77 108 159]
[ 65 91 137]]
[[101 148 222]
[ 96 146 222]
[ 91 146 221]
...,
[ 56 80 132]
[ 3 22 65]
[ 0 3 40]]
...,
[[ 21 40 45]
[ 24 37 45]
[ 34 41 50]
...,
[ 20 34 57]
[ 7 24 50]
[ 8 27 54]]
[[ 17 35 36]
[ 20 32 38]
[ 22 29 38]
...,
[ 13 29 52]
[ 28 45 72]
[ 41 59 90]]
[[ 15 31 30]
[ 19 31 35]
[ 21 28 37]
...,
[ 13 29 52]
[ 48 64 93]
[ 71 90 123]]]
'''
# 输出将灰度图片重新转换为BGR形式图片后的内容
print(img2)
'''
[[[170 170 170]
[171 171 171]
[170 170 170]
...,
[111 111 111]
[169 169 169]
[193 193 193]]
[[167 167 167]
[167 167 167]
[166 166 166]
...,
[127 127 127]
[120 120 120]
[102 102 102]]
[[165 165 165]
[163 163 163]
[162 162 162]
...,
[ 93 93 93]
[ 33 33 33]
[ 14 14 14]]
...,
[[ 39 39 39]
[ 38 38 38]
[ 43 43 43]
...,
[ 39 39 39]
[ 30 30 30]
[ 33 33 33]]
[[ 33 33 33]
[ 32 32 32]
[ 31 31 31]
...,
[ 34 34 34]
[ 51 51 51]
[ 66 66 66]]
[[ 29 29 29]
[ 31 31 31]
[ 30 30 30]
...,
[ 34 34 34]
[ 71 71 71]
[ 98 98 98]]]
'''
代码清单③ 负片功能实现
import numpy as np
import cv2
# 读入图片
img = cv2.imread("lena.jpg")
# 获取高度和宽度,注意索引是高度在前,宽度在后
height = img.shape[0]
width = img.shape[1]
# 生成一个空的三维张量,用于存放后续三个通道的数据
negative_file = np.zeros((height,width,3))
# 将BGR形式存储的彩色图片拆分成三个颜色通道,注意颜色通道的顺序是蓝、绿、红
b,g,r = cv2.split(img)
# 进行负片化处理,求每个通道颜色的补色
r = 255 - r
b = 255 - b
g = 255 - g
# 将处理后的结果赋值到前面生成的三维张量中
negative_file[:,:,0] = b
negative_file[:,:,1] = g
negative_file[:,:,2] = r
# 看一下生成图片的数据
negative_file
'''
array([[[ 142., 103., 28.],
[ 146., 102., 25.],
[ 151., 103., 25.],
...,
[ 197., 162., 89.],
[ 136., 99., 43.],
[ 106., 73., 23.]],
[[ 148., 106., 31.],
[ 152., 106., 29.],
[ 158., 106., 30.],
...,
[ 176., 143., 80.],
[ 178., 147., 96.],
[ 190., 164., 118.]],
[[ 154., 107., 33.],
[ 159., 109., 33.],
[ 164., 109., 34.],
...,
[ 199., 175., 123.],
[ 252., 233., 190.],
[ 255., 252., 215.]],
...,
[[ 234., 215., 210.],
[ 231., 218., 210.],
[ 221., 214., 205.],
...,
[ 235., 221., 198.],
[ 248., 231., 205.],
[ 247., 228., 201.]],
[[ 238., 220., 219.],
[ 235., 223., 217.],
[ 233., 226., 217.],
...,
[ 242., 226., 203.],
[ 227., 210., 183.],
[ 214., 196., 165.]],
[[ 240., 224., 225.],
[ 236., 224., 220.],
[ 234., 227., 218.],
...,
[ 242., 226., 203.],
[ 207., 191., 162.],
[ 184., 165., 132.]]])
'''
# 将生成的图片保存起来,注意存储图片文件名中的扩展名
cv2.imwrite("negative_lena.jpg",negative_file)
点算子:基于像素变换,在这一类图像变换中,仅仅根据输入像素值(有时可加上某些额外信息)计算相应的输出像素值。 邻域算子:基于图像区域进行变换。
代码清单④ 对图片亮度与对比度转换演示
import cv2
import numpy as np
# 方法1:通过addWeighted()函数来实现
def convert_img1(img, alpha, beta):
blank = np.zeros(img.shape, img.dtype) # dtpye is uint8
return cv2.addWeighted(img, alpha, blank, 0, beta)
# 方法2: 通过for循环手动实现,与addWeighted()函数内部实现原理一样
def convert_img2(img, alpha, beta):
rows, cols, channel = img.shape
new_img = np.zeros(img.shape, img.dtype)
for i in range(0,rows):
for j in range(0,cols):
for k in range(0,channel):
# np.clip() 将数值限制在[0,255]区间,防止数字溢出
new_img[i,j,k] = np.clip(
alpha * img[i,j,k] + beta,0,255)
return new_img
img = cv2.imread('lena.jpg')
cv2.imwrite('converted_lena_1.jpg', convert_img1(img,2.2,50))
cv2.imwrite('converted_lena_2.jpg', convert_img2(img,2.2,50))
代码清单⑤ 图像裁剪演示
import cv2
import numpy as np
img = cv2.imread('lena.jpg')
print(img.shape)
# (121, 121, 3)
new_img = img[20:120,20:120]
cv2.imwrite('new_img.jpg',new_img)
代码清单⑥ 使用OpenCV变换图像尺寸
import cv2
import numpy as np
img = cv2.imread('lena.jpg')
print(img.shape)
# (121, 121, 3)
new_img = cv2.resize(img,(40,40),interpolation=cv2.INTER_AREA)
cv2.imwrite('new_img1.jpg', new_img)
print(new_img.shape)
# (40, 40, 3)
new_img2 = cv2.resize(img,None,fx=0.5, fy=0.6,interpolation=cv2.INTER_AREA)
print(new_img2.shape)
# 注意图像的宽对应的是列数,高对应的是行数
# (73, 60, 3)
cv2.imwrite('new_img2.jpg',new_img2)
代码清单⑦ 使用OpenCV实现图像旋转
import cv2
import numpy as np
img = cv2.imread('lena.jpg')
rows, cols, _ = img.shape
# 第一个参数为旋转中心,第二个为旋转角度,第三个为旋转后的缩放因子
rotated_img = cv2.getRotationMatrix2D((cols/2,rows/2),45,0.4)
cv2.imwrite('dst.jpg',dst)
代码清单⑧ 为图像添加噪声
import cv2
import numpy as np
import random
# 添加椒盐噪声
def salt_and_pepper_noise(img, percentage):
rows, cols = img.shape
num = int(percentage * rows * cols)
for i in range(num):
x = random.randint(0,rows - 1)
y = random.randint(0,cols - 1)
if random.randint(0,1) == 0:
img[x,y] = 0 # 黑色噪点
else:
img[x,y] = 255 # 白色噪点
return img
# 添加高斯随机噪声
def gaussian_noise(img, mu, sigma, k):
rows, cols = img.shape
for i in range(rows):
for j in range(cols):
# 生成高斯分布的随机数,与原始数据相加后要取整
value = int(img[i,j] + k * random.gauss(mu=mu,
sigma=sigma))
# 限定数据值的上下边界
value = np.clip(a_max=255,a_min=0,a=value)
img[i,j] = value
return img
img = cv2.imread('lena.jpg')
# 转换为灰度图像
gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imwrite('gray_lena.jpg',gray_img)
# 需要复制一份,不然是对图像的引用,后面的操作会重叠
gray_img2 = gray_img.copy()
# 保存椒盐噪声图像
cv2.imwrite('salt_and_pepper.jpg',
salt_and_pepper_noise(gray_img,0.3))
# 保存高斯噪声图像
cv2.imwrite('gaussian.jpg',
gaussian_noise(gray_img2, 0, 1, 32))
代码清单⑨ 图像滤波演示
import cv2
import numpy as np
import random
salt_and_pepper_img = cv2.imread('salt_and_pepper.jpg')
gaussian_img = cv2.imread('gaussian.jpg')
# 2维卷积
# 得到一个5*5大小的矩阵作为卷积核,矩阵中的每个值都为0.04
kernel = np.ones((5,5),np.float32) / 25
conv_2d_img = cv2.filter2D(salt_and_pepper_img, -1, kernel)
cv2.imwrite('filter_2d_img.jpg', conv_2d_img)
# 中值滤波
# 参数5表示选择附近5*5区域的像素值进行计算
median_blur_img = cv2.medianBlur(salt_and_pepper_img,5)
cv2.imwrite('median_blur_img.jpg', median_blur_img)
# 高斯模糊
# 标准差参数设置为0是指根据窗口大小(5,5)来自行计算高斯函数标准差
gaussian_blur_img = cv2.GaussianBlur(gaussian_img, (5,5), 0)
cv2.imwrite('gaussian_blur_img.jpg', gaussian_blur_img)
# 双边滤波
# cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace)
# 9 代表邻域直径,两个参数75分别代表值域与空域标准差
bilateral_filter_img = cv2.bilateralFilter(gaussian_img, 9, 75, 75)
cv2.imwrite('bilateral_filter_img.jpg', bilateral_filter_img)
对添加过椒盐噪声图片经过二维卷积滤波后的结果 对添加过椒盐噪声图片进行中值滤波后的结果 对经过高斯噪声污染后的图片进行高斯滤波后的结果 对经过高斯噪声污染后的图片进行双边滤波后的结果
推荐阅读
一份职位信息的精准推荐之旅,从AI底层架构说起
Uber提出损失变化分配方法LCA,揭秘神经网络“黑盒”
阿里云智能运维的自动化三剑客
掌握这些步骤,机器学习模型问题药到病除
6张拓扑图揭秘中心化交易所的5种行为, 原来中心化比你想象的重要!
分布式存储春天已来Storj首登top10; Cardano排名上升; 以太坊比特币活跃地址双下降 | 数据周榜
华为愿出售5G技术渴望对手;苹果将向印度投资10亿美元;华为全联接大会首发计算战略;腾讯自研轻量级物联网操作系统正式开源……
我愿出 2 倍工资,挖这个被裁的程序员!
厉害!接班马云的为何是张勇?
你点的每个“在看”,我都认真当成了喜欢“