opencv:
基础知识:
熟悉python语言编程 c/c++编程基础 矩阵运算
windows下用python语言
IDEA: pycharm
安装opencv-python库: pip install opencv-python
import cv2 as cv
img = cv.imread("../pics/20.jpg")
cv.imshow("img", img)
cv.waitKey() # 等待用户操作
cv.destroyAllWindows() # 释放窗口
注意: cv.imread会将图片读成矩阵格式
格式: img = imread(图片路径名字, 读取方式(0: 灰度图片, 1: 彩色图片))
参数1: 读取的图片的路径
参数2: 读取的方式, 灰度(0)还是彩色(1)
返回值: 图片的矩阵形式
功能: 打开文件,读取文件内容, 将文件转换成矩阵形式
import cv2 as cv
# 读取路径为../pics/20.jpg, 读取方式是一个灰度
img = cv.imread("../pics/20.jpg", 0)
cv.namedWindow("窗口名字")
cv.imshow("窗口名字", 图片的矩阵格式)
cv.waitKey(时间)# 时间单位是ms(0表示无限制等待,直到用户按任意键结束)
cv.destroyAllWindows()# 释放所有窗口
# 释放指定窗口
# cv.destroyWindow("窗口名字")
图像处理基本函数: imread()、imshow()、waitKey()、destroyAllWindows()、imwrite()
处理图像就是操作img
img是通过什么方式表示一副图像?
图像的表示:
二值图像: 图像中仅有两种颜色: 黑或白
图像: 由多个像素点构成,按照行列分布
用一个矩阵表示图像,
例如 图像 512 * 512 大小,则用 512 * 512(二维矩阵) 矩阵表示图像
像素点是黑色,则对应的矩阵值是 0
像素点是白色,则对应的矩阵值是 255
每一个像素点用一个字节来存储, 矩阵(二维数组) 每一个元素取值范围 0~255
灰度图像: 图像中颜色, 共计由256级 0~255
黑色 – 白色
图像 --> 用矩阵表示
矩阵中每一个元素存储图像中对应的像素点的值
图像的表示方法: img = cv.imread()
二值图像: 0(黑色) 、 255(白色)
灰度图像: 黑色 -> 白色 共计分了256等级 ( 0 黑色 --> 255 白色)
彩色图像:
结论:
【图像表示方法总结】:
【像素处理】:
一、二值图像及灰度图像
小栗子: 读取一个灰度图像,对其中的像素访问和修改
import cv2 as cv
img = cv.imread("../pics/20.jpg")
img[0:100, 0:100] = 0
cv.imshow("img", img)
cv.waitKey(0)
cv.destroyAllWindows()
【栗子】: 使用numpy生成一个蓝色(绿色、红色)的 300 *300 的矩阵
import numpy as np
import cv2 as cv
# 蓝色矩阵
blue = np.zeros((300, 300, 3), dtype=np.uint8)
blue[:, :, 0] = 255
print("blue")
cv.imshow("blue", blue)
# 绿色矩阵
green = np.zeros((300, 300, 3), dtype=np.uint8)
green[:, :, 1] = 255
print("green")
cv.imshow("green", green)
# 红色矩阵
red = np.zeros((300, 300, 3), dtype=np.uint8)
red[:, :, 2] = 255
print("red")
cv.imshow("red", red)
cv.waitKey(0)
cv.destroyAllWindows()
【栗子2】: 画一个条纹状的 蓝绿红 300 * 300 的图像
import numpy as np
import cv2 as cv
bgr = np.zeros((300, 300, 3), dtype=np.uint8)
# 蓝色
bgr[:, 0:100, 0] = 255
# 绿色
bgr[:, 100:200, 1] = 255
# 红色
bgr[:, 200:300, 2] = 255
cv.imshow("bgr", bgr)
cv.waitKey(0)
cv.destroyAllWindows()
打印某一个像素bgr的值
img = cv.imread("../pics/20.jpg", 1)
# 读取第100行,100列像素位置的bgr值
(b, g, r) = img[100, 100]
print(b, g ,r)
【栗子】: 在图像(彩色)中画一个水平和垂直线
import cv2 as cv
img = cv.imread("../pics/20.jpg", 1)
# B通道
img[:, 0, 0] = 0
img[0, :, 0] = 0
# G通道
img[:, 0, 1] = 0
img[0, :, 1] = 0
# R通道
img[:, 0, 2] = 0
img[0, :, 2] = 0
print(img.shape)
cv.imshow("img", img)
cv.waitKey(0)
cv.destroyAllWindows()
【栗子】: 增强图像的像素值
import cv2 as cv
img = cv.imread("../pics/20.jpg", 0)
(row, col) = img.shape
cv.imshow("pre", img)
for i in range(0,row):
for j in range(0,col):
tmp = img[i][j] +90
if(tmp > 255):
tmp = tmp-255
img[i][j] = tmp
cv.imshow("after", img)
cv.waitKey(0)
使用numpy.array提供的item()和itemset()函数访问和修改像素.
两个函数经过优化处理,能够大幅度提高处理效率
比直接用索引访问快的多、可读性更好
访问灰度图像:
访问彩色图像:
【栗子1】: 修改和访问灰度图像
import numpy as np
img = np.random.randint(10, 99, size=[5, 5], dtype=np.uint8)
print(img)
print(img.item(3, 2))
img.itemset((3, 2), 255)
print(img.item(3, 2))
【栗子2】: 生成一个灰度图像,其中的像素值为随机数
import numpy as np
import cv2 as cv
img = np.random.randint(0,255, size=[256, 256], dtype=np.uint8)
cv.imshow("img", img)
cv.waitKey(0)
cv.destroyAllWindows()
【栗子3】: 读取一个灰度图片,并对其进行像素值访问
import numpy as np
import cv2 as cv
img = cv.imread("../pics/20.jpg", 0)
cv.imshow("before", img)
for i in range(0,255):
for j in range(10,40):
img.itemset((i,j), 255)
cv.imshow("after", img)
cv.waitKey(0)
cv.destroyAllWindows()
【栗子4】: 生成一个彩色图像
# 生成一个256 * 256的随机彩色图像
import numpy as np
import cv2 as cv
img = np.random.randint(0, 255, size=[256, 256, 3], dtype=np.uint8)
cv.imshow("img", img)
cv.waitKey(0)
cv.destroyAllWindows()
处理图像过程中,可能回对图像某一个特定区域感兴趣,该区域称为感兴趣区域(Region of Interest, ROI)
设定感兴趣区域后,就可以对该区域进行整体操作:
【栗子】: 对脸部打码
import cv2 as cv
import numpy as np
img = cv.imread("../../pics/20.jpg", 0)
# head = img[15:215, 150:330]
mask = np.random.randint(0, 255, size=[200, 180], dtype=np.uint8)
img[15:215, 150:330] = mask
cv.imshow("img", img)
cv.waitKey(0)
cv.destroyAllWindows()
RGB图在opencv中按照BGR的形式存储,在图像处理过程中根据实际,对通道进行拆分和合并
通道拆分:
b = img[:,:,0]
g = img[:,:,1]
r = img[:,:,2]
b,g,r = cv.splite(img)
【栗子】: 将彩色图像中的RGB通道分离处理,并单独成图显示
import cv2 as cv
img = cv.imread("../../pics/20.jpg")
b, g, r = cv.split(img)
cv.imshow("b", b)
cv.imshow("g", g)
cv.imshow("r", r)
cv.waitKey(0)
cv.destroyAllWindows()
【栗子】: 将分离出来的bgr通道合并成 rgb通道并显示出来
import cv2 as cv
img = cv.imread("../../pics/20.jpg")
b, g, r = cv.split(img)
rgb = cv.merge([r, g, b])
cv.imshow("rgb", rgb)
cv.imshow("bgr", img)
cv.waitKey(0)
cv.destroyAllWindows()
shape:
size: 返回图像的大小: 行数 * 列数 * 通道个数
dtype: 返回图像数据类型
import cv2 as cv
img = cv.imread("../../pics/20.jpg")
# 矩阵的维度
print(img.shape)
# 所占字节数
print(img.size)
# 元素的类型
print(img.dtype)
img_grey = cv.imread("../../pics/20.jpg", 0)
# 矩阵的维度
print(img_grey.shape)
# 所占字节数
print(img_grey.size)
# 元素的类型
print(img_grey.dtype)
import cv2 as cv
# 读取一个灰度图像
img = cv.imread("../../pics/20.jpg", 0)
img[:,:] += 20
cv.imshow("img", img)
cv.waitKey(0)
cv.destroyAllWindows()
处理图像过程中,进程需要对图像进行加法运算.可以它通过"+"或者 cv2.add()函数实现
用加号预运算符对图像a和图像b进行求和运算规则如下:
a+b = mod(a+b, 255)
使用函数cv2.add()计算像素值和规则:
【栗子】: 使用add添加像素
import cv2 as cv
img = cv.imread("../../pics/20.jpg")
cv.imshow("before", img)
img = cv.add(img, 90)
cv.imshow("img", img)
cv.waitKey(0)
cv.destroyAllWindows()
【栗子】: 使用add进行两张图片相加
import cv2 as cv
img_16 = cv.imread("../../pics/16.jpg")
img_18 = cv.imread("../../pics/18.jpg")
img_20 = cv.imread("../../pics/20.jpg")
shape_500_300_20 = img_20[0:300, 0:500]
shape_500_300_16 = img_16[0:300, 0:500]
comb = cv.add(shape_500_300_20, shape_500_300_16)
cv.imshow("comb", comb)
cv.waitKey(0)
cv.destroyAllWindows()
注意: add函数是 两个相加,如果值超过255就取255 .
加权和: 计算两幅图像的像素之和时,将每幅图像权重考虑进来,使用公式
dst = saturate(src1 * a + src2 * b + r)
对应opencv()中的函数:
dst = cv2.addWeighted(src1, a, src2, b, r)
import cv2 as cv
img_16 = cv.imread("../../pics/16.jpg")
img_20 = cv.imread("../../pics/20.jpg")
dali = img_20[0:300, 0:500]
mao = img_16[0:300, 0:500]
comb = cv.addWeighted(dali, 0.1, mao, 0.9, 0)
cv.imshow("comb", comb)
cv.waitKey(0)
cv.destroyAllWindows()
按位逻辑运算在图形处理中是一种非常重要的处理方式:
函数 | 作用 |
---|---|
cv.bitwise_and() | 按位与 |
cv.bitwise_or() | 按位或 |
cv.bitwise_xor() | 按位异或 |
cv.bitwise_not() | 按位取反 |
【掩模】:
使用掩模参数时,操作只会在掩模值为空的像素点上执行,在opencv中的函数如下:
img3 = cv.add(img1, img2, mask=mask)
import numpy as np
img = cv.imread("../../pics/20.jpg")
w, h, c = img.shape
mask = np.zeros((w, h), dtype=np.uint8)
mask[40:160, 80:160] = 255
mask[40:200, 40:80] = 255
exam = cv.bitwise_and(img, img, mask=mask)
cv.imshow("mask", mask)
cv.imshow("exam", exam)
cv.waitKey(0)
cv.destroyAllWindows()
位平面分解:
概念: 将灰度图中处于同一比特位上的二进制像素值进行组合,得到一幅二进制图像,该图像称为灰度图像的一个位平面
在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
通过提取灰度像素点二进制像素值得每一个比特位组合,可以得到8个位平面,组成8个图像.
import numpy as np
import cv2 as cv
img = cv.imread("../../pics/20.jpg", 0)
w, h = img.shape
mat = np.ones((w, h), dtype=np.uint8)
rest0 = cv.bitwise_and(img, mat) * 128
cv.imshow("img", img)
cv.imshow("rest0", rest0)
cv.waitKey(0)
cv.destroyAllWindows()
提取位平面
阈值处理:
通过按位异或运算可以实现图像的加密和解密
原始图像与神秘图像进行按位异或,可以实现加密
将加密后的图像与密钥图像再次按位异或,实现解密
【栗子】: 生成一个随机的密钥,给图片加密.
import cv2 as cv
import numpy as np
img = cv.imread("../../pics/20.jpg")
dst = np.random.randint(0, 255, img.shape, dtype=np.uint8)
# 给图像加密
img = cv.bitwise_xor(img, dst)
cv.imshow("withkey", img)
# 图像解密
img = cv.bitwise_xor(img, dst)
cv.imshow("unshiftkey", img)
cv.waitKey(0)
cv.destroyAllWindows()
将一幅二值图像嵌入到一个载体图像的第0个位平面
将载体图像的第0个位平面提取出来,获得二值图像的信息
嵌入过程: 将载体图像的第0个位平面替换位数字水印信息(一幅二值图像)
提取过程: 将载体图像的最低有效位所构成的第0个位平面提取出来,得到数字水印信息
嵌入式过程:
嵌入水印图像:
提取水印图像:
import cv2 as cv
import numpy as np
# 载体图像
img = cv.imread("../../pics/16.jpg", 0)
r, c = img.shape
# 将第0个位平面全部置为0
t254 = np.ones((r, c), dtype=np.uint8) * 254
exam = cv.bitwise_and(img, t254)
# 读取数字水印
watermark = cv.imread("../../pics/18.jpg", 0)
# 将水印 --> 二值图像
w = watermark[:, :] > 1
watermark[w] = 1
# 水印嵌入载体图像
e = cv.bitwise_or(exam, watermark)
# 水印的提取
r,c = e.shape
t1 = np.ones((r,c), dtype=np.uint8)
wm = cv.bitwise_and(e, t1)
w = wm[:,:] > 0
wm[w] = 255
cv.imshow("wm", wm)
cv.waitKey(0)
cv.destroyAllWindows()