灰度图像 - 单通道
彩色图像 - 三通道 (B, G, R)
一般步骤
import cv2 as cv # 导入OpenCV支持(cv2是包的名称不是版本号)
import numpy as np # 所有图像数据都是以 numpy 数组方式存储
imread(filename[,flags]) # imread 函数,读取图像
# filename 表示文件路径, []内可以不填
imshow(winname, mat) # imshow 函数,显示图像
# winname 表示窗口标题, mat 表示图像对象
# 加载通道顺序
显示与等待时间
cv.wajitKey(0)
表示一直等待,直到任意一个键盘操作
cv.waitKey(1000)
表示等待1000ms即1s
如果不加, 图片会一闪而过
import cv2 as cv
import numpy as np
def show_image():
image = cv.imread("E:/data/lena.jpg")
cv.imshow("input", image)
cv.waitKey(0)
cv.destroyAllWindows()
show_image()
图像色彩转换
从一个色彩空间转换到另外一个色彩空间
信息传递与损失
过程可逆与不可逆
cv.cvtColor(src,code[,dst[,dstCn]])->dst
# src表示输入图像, 类型CV_8U(np.uint8字节类型)、CV_32F(np.float32浮点数类型)
code表示:
cv::COLOR_BGR2RGB = 4 # 通道交换 cv::COLOR_BGR2GRAY = 6 # 彩色到灰度 cv::COLOR_GRAY2BGR = 8 # 灰度到彩色(信息损失不可逆) cv::COLOR_BGR2HSV = 40 # 可以双线转换
示例:
import cv2 as cv
import numpy as np
def color_space_demo():
image = cv.imread("lena.jpg")
cv.imshow("lena", image)
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
ycrcb = cv.cvtColor(image, cv.COLOR_BGR2YCrCb)
cv.imshow("hsv", hsv)
cv.imshow("ycrcb", ycrcb)
cv.waitKey(0)
cv.destroyAllWindows()
color_space_demo()
opencv-python中一切图像数据皆numpy array
*• numpy.array(object, dtype=None, , copy=True, order=‘K’, subok=False, ndmin=0, like=None)
object 数组
dtype 数据类型
*•numpy.zeros(shape, dtype=float, order=‘C’, , like=None)
数组维度
dtype 数据类型
*•numpy.asarray(a, dtype=None, order=None, , like=None)
数组对象
dtype 数据类型
•numpy.reshape(a, newshape, order=‘C’)
数组维度
dtype 数据类型
import numpy as np
np.array([[1, 2],[3, 4]], dtype=np.uint8)
创建图像
•np.zeros ->创建一个黑色背景图像
•np.zeros_like->创建一个与输入图像大小一致的黑色背景图像
•np.ones创建一个全部像素值是1的图像
图像赋值
•图像赋值就是给numpy array数组赋值
•m = np.zeros((3, 3, 3), dtype=uint8)
•m[:] = 255
•创建数组m,然后赋值为255(白色)
•m[:] = (255,0,0)
•创建数组m,然后赋值为(255,0,0)蓝色
代码演示
def numpy_demo():
m1 = np.array([[2,3], [4, 5]], dtype=np.uint8)
print(m1)
m2 = np.ones((4,4,3), dtype=np.uint8)
print(m2)
m2[:] = (255, 0, 0)
print(m2)
m3 = np.zeros((4,4,3),dtype=np.uint8)
print(m3)
m3[:]=255
print(m3)
numpy_demo()
C:\use\anaconda\envs\openvino\python.exe C:/use/E/桌面/cv/opencv/test.py
[[2 3]
[4 5]]
[[[1 1 1]
[1 1 1]
[1 1 1]
[1 1 1]][[1 1 1]
[1 1 1]
[1 1 1]
[1 1 1]][[1 1 1]
[1 1 1]
[1 1 1]
[1 1 1]][[1 1 1]
[1 1 1]
[1 1 1]
[1 1 1]]]
[[[255 0 0]
[255 0 0]
[255 0 0]
[255 0 0]][[255 0 0]
[255 0 0]
[255 0 0]
[255 0 0]][[255 0 0]
[255 0 0]
[255 0 0]
[255 0 0]][[255 0 0]
[255 0 0]
[255 0 0]
[255 0 0]]]
[[[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]][[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]][[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]][[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]]]
[[[255 255 255]
[255 255 255]
[255 255 255]
[255 255 255]][[255 255 255]
[255 255 255]
[255 255 255]
[255 255 255]][[255 255 255]
[255 255 255]
[255 255 255]
[255 255 255]][[255 255 255]
[255 255 255]
[255 255 255]
[255 255 255]]]进程已结束,退出代码0
def numpy_demo():
black = np.zeros((512, 512, 3), dtype=np.uint8)
black[:,0:255] = 255
h,w,c = black.shape
print(h,w,c)
cv.imshow("black", black)
cv.waitKey(0)
cv.destroyAllWindows()
numpy_demo()
像素遍历本质就是numpy数组访问
假设变量image
获取图像维度信息: image.shape
图像访问像素: image[row, col]
图像赋值像素: image[row, col] = (b,g,r)
b, g, r = image[row, col]
image[row, col] = (255-b, 255-g, 255-r)
读写像素,灰度图像:
pv = image[row, col]
image[row, col] = 255-pv
def visit_pixel_demo():
image = cv.imread("lena.jpg")
cv.imshow("lina", image)
h, w, c = image.shape
for row in range(h):
for col in range(w):
b, g, r = image[row, col]
# 反色
image[row, col] = (255 - b, 255 - g, 255 - r)
cv.imshow("visited", image)
cv.waitKey(0)
cv.destroyAllWindows()
visit_pixel_demo()
cv.add(src1, src2[, dst[, mask[, dtype]]]) ->dst
cv.subtract(src1,src2[,dst[,mask[,dtype]]])->dst
cv.multiply(src1,src2[,dst[,scale[,dtype]]])->dst
cv.divide(src1, src2[, dst[, scale[, dtype]]])->dst
src1 & src2表示图像
加法,保证不越界:saturate(src1 + src2)-》0~255
超过255取255,小于0取0
def arithmetic_demo():
image1 = cv.imread("lena.jpg")
h, w, c = image1.shape
image2 = np.zeros_like(image1)
image2[:,:] = (110, 0, 250)
mask = np.zeros((h, w), dtype=np.uint8)
mask[100:200,100:200] = 1;
cv.imshow("img1", image1)
cv.imshow("img2", image2)
added = cv.add(image1, image2, mask = mask)
cv.imshow("added", added)
cv.waitKey(0)
cv.destroyAllWindows()
arithmetic_demo()
typedef void(* cv::TrackbarCallback) (int pos, void *userdata)
完成事件响应函数的声明与实现
// pos 滑块所在位置 userdata 用户数据
# 完成事件响应函数的声明与实现
def trackbar_callback (pos):
print(pos)
cv.namedWindow(winname [, flags]) -> None
# 参数: winname表示窗口标题
# 参数flags支持的flag有:
# WINDOW_NORMAL – 可以调整窗口大小
# WINDOW_AUTOSIZE – 根据图像大小自动适应,不可调
# WINDOW_KEEPRATIO – 可以保持比例窗口,调整大小
•RGB值表示亮度
•RGB(0, 0,0) 黑色 - 》 RGB(255,255,255)白色
•add函数支持图像+图像与图像+常量方式
•subtract函数支持图像+图像与图像+常量方式
•通过他们可以修改图像的亮度
•动态调整,基于滚动条修改常量值,实现动态修改图像亮度并刷新显示
•创建图像窗口
•创建滚动条组件
•在窗口显示图像
•拖拉滚动条修改图像亮度
def trackbar_callback(pos):
print(pos)
def trackbar_demo():
image = cv.imread("E:/data/butterfly.jpg")
cv.namedWindow("trackbar_demo", cv.WINDOW_KEEPRATIO)
# 创建滚动条
cv.createTrackbar("lightness", "trackbar_demo", 0, 200, trackbar_callback)
cv.imshow("trackbar_demo", image)
while True:
# 获取该窗口滚动条的位置
pos = cv.getTrackbarPos("lightness", "trackbar_demo")
image2 = np.zeros_like(image)
image2[:, :] = (np.uint8(pos), np.uint8(pos), np.uint8(pos))
# 提升亮度
result = cv.add(image, image2)
# 降低亮度
# result = cv.subtract(image, image2)
cv.imshow("trackbar_demo", result)
c = cv.waitKey(1)
if c == 27:
break
cv.waitKey(0)
cv.destroyAllWindows()
trackbar_demo()
cv.waitKey( [, delay] ) ->retval
delay如果没有声明或者delay=0,表示一直阻塞
delay大于0,表示阻塞指定毫秒数
retval返回的对应键盘键值,注意:在不同的操作系统中可能会有差异!
典型的retval = 27是ESC按键
通过python的选择语句
推荐使用if-elif-else;switch-case方式python3.10支持
if <expr>:
<statement(s)>
elif <expr>:
<statement(s)>
elif <expr>:
<statement(s)>
...
else:
<statement(s)>
image = cv.imread("E:/data/butterfly.jpg")
cv.namedWindow("keyboard_demo", cv.WINDOW_AUTOSIZE)
cv.imshow("keyboard_demo", image)
while True:
c = cv.waitKey(10)
# 按ESC退出
if c == 27:
break
# 按0回复原图BGR显示
elif c == 48:
cv.imshow("keyboard_demo", image)
# 按1显示HSV图像
elif c == 49:
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
cv.imshow("keyboard_demo", hsv)
# 按2显示YCrCb
elif c == 50:
ycrcb = cv.cvtColor(image, cv.COLOR_BGR2YCrCb)
cv.imshow("keyboard_demo", ycrcb)
# 按3显示RGB图像
elif c == 51:
rgb = cv.cvtColor(image, cv.COLOR_BGR2RGB)
cv.imshow("keylboard_demo", rgb)
cv.waitKey(0)
cv.destroyAllWindows()
空间换时间,避免重复计算,节约计算时间
Gamma校正
G a m m a = k ∗ E r = 255 ∗ E l o g ( p ( x , y ) / 255 ) ∗ g a m m a Gamma =k*E^r=255*E ^ {log(p(x,y)/255)*gamma} Gamma=k∗Er=255∗Elog(p(x,y)/255)∗gamma
•公式p(x, y)表示输入图像像素值, gamma取值范围0.05~5之间
•像素值取值范围在0~255之间,每一个值对应一个输出值,这样映射关系,可以先建立查找表LUT
•根据输入得像素值作为index,在LUT中直接映射读取得到gamma校正之后得值
•对256x256大小的图像,计算量对比:
•不应用找表计算gamma - 65536次,
•应用查找表计算gamma – 256次
cv.applyColorMap(src, colormap[, dst]) ->dst
# 第一个参数输入图像
# 第二个参数是颜色表
# dst返回图像
def lut_demo():
cv.namedWindow("lut-demo", cv.WINDOW_NORMAL)
lut = [[255, 0, 255], [125, 0, 0], [127, 255, 200], [200,127, 127], [0, 255, 255]]
m1 = np.array([[2, 1, 3, 0], [2, 2, 1, 1], [3, 3, 4, 4], [4,4,1,1]])
m2 = np.zeros((4, 4, 3), dtype=np.uint8)
for i in range(4):
for j in range(4):
index = m1[i, j]
m2[i, j] = lut[index]
cv.imshow("lut-demo", m2)
cv.waitKey(0)
cv.destroyAllWindows()
lut2 = np.zeros((256), dtype=np.uint8)
gamma = 0.7
for i in range(256):
print(i, "--", np.log(i / 255.0))
lut2[i] = int(np.exp(np.log(i/255.0) * gamma) * 255.0)
print(lut2)
image = cv.imread("E:/data/butterfly.jpg")
dst = cv.LUT(image, lut2)
cv.imshow("butterfly-gamma", dst)
cv.imshow("input", image)
cv.namedWindow("butterfly-gamma", cv.WINDOW_AUTOSIZE)
h, w, c = image.shape
for row in range(h):
for col in range(w):
b, g, r = image[row, col]
image[row, col] = (lut2[b], lut2[g], lut2[r])
cv.imshow("butterfly-gamma", image)
# 自定义查找表
lut3 = np.zeros((256, 1, 3), dtype=np.uint8)
for i in range(256):
print(i, "--", np.log(i / 255.0))
c = int(np.exp(np.log(i/255.0) * gamma) * 255.0)
lut3[i, 0] = [c, c, c]
print(lut3)
dst = cv.LUT(image, lut3)
cv.imshow("butterfly-gamma", dst)
# 系统查找表
dst = cv.applyColorMap(image, cv.COLORMAP_PINK)
cv.imshow("butterfly-pink", dst)
cv.waitKey(0)
cv.destroyAllWindows()
lut_demo()