OpenCV学习笔记
图像色彩空间转换
jpg图片的色彩空间为RGB,png图片多一个透明通道,OpenCV读取到的图像色彩空间为BGR
色彩空间转换方法
gary = cv.cvtColor(image, cv.COLOR_BGR2GRAY) # 转换为灰度
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV) # 转换为hsv
hsv = cv.cvtColor(image, cv.COLOR_HSV2BGR) # hsv转换为BGR,H通道范围为0-180,其余为0-255
图像对象的创建于赋值
image = cv.imread("D:/Code/1.jpg") # (666, 999, 3)
print(image.shape) # 输出图片的高,宽,通道 h, w, c
roi = image[60:200, 50:100, :] # 将图片一部分区域设置为roi区域
blank = np.zeros_like(image) # 创建一个和图片一样大小的空白图片
blank[60:200, 50:100, :] = image[60:200, 60:110, :] # 将图片的一部分拷贝到空白图片中
两种复制图像方法的区别
blank = np.copy(image)
这种方法复制的图片,是通过copy方法将image图片复制在blank下,对blank的操作不影响image
blank = image
这种方法相当于blank和image为同一个数据,对blank修改后都会同时影响两个的图像数据
图像像素的读写操作
将图像进行反色操作
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)
图像像素的算数操作
在做两个图像像素运算时,要保证两个图片的大小和通道数都一致,才能进行运算
image = cv.imread("D:/Code/1.jpg") # (666, 999, 3)
cv.imshow("input", image)
blank = np.zeros_like(image)
blank[:, :] = (10, 10, 10) # 为blank图像像素的通道赋值
cv.imshow("blank", blank)
result = cv.add(image, blank) # 相加
result = cv.subtract(image, blank) # 相减
result = cv.multiply(image, blank) # 相乘
result = cv.divide(image, blank) # 相除
TrackBar滚动条操作调整亮度
def print_value(a):
print(a)
def adjust_lightness_demo():
image = cv.imread("D:/Code/1.jpg") # (666, 999, 3)
cv.namedWindow("input", cv.WINDOW_AUTOSIZE) # 创建窗口 (窗口名,窗口大小自适应图片大小并且不能更改)
cv.createTrackbar("lightness", "input", 0, 255, print_value) # 创建滚动条 (滚动条名字,滚动条属于的窗口名字,滚动条取值范围,回调函数)
cv.imshow("input", image)
blank = np.zeros_like(image)
while True:
pos = cv.getTrackbarPos("lightness", "input") # 获取当前滚动条的值
blank[:, :] = (pos, pos, pos)
result = cv.add(image, blank)
cv.imshow("result", result)
c = cv.waitKey(1) # 等待用户触发事件时间
if c == 27: # 如果按下ESC(ASCII码为27)
cv.destroyAllWindows()
cv.namedWindow(winname, flags=None)
- winname:创建的窗口名字
- flags:WINDOW_AUTOSIZE 窗口大小自动适应图片大小,并且不可手动更改。
WINDOW_NORMAL 用户可以改变这个窗口大小
WINDOW_OPENGL 窗口创建的时候会支持OpenGL
TrackBar滚动条操作调整对比度
def adjust_contrast_demo():
image = cv.imread("D:/Code/1.jpg") # (666, 999, 3)
cv.namedWindow("input",cv.WINDOW_AUTOSIZE)
cv.createTrackbar("lightness", "input", 0, 255, print_value)
cv.createTrackbar("contrast", "input", 0, 255, print_value)
cv.imshow("input", image)
blank = np.zeros_like(image)
while True:
light = cv.getTrackbarPos("lightness", "input")
contrast = cv.getTrackbarPos("contrast", "input")/100
print("light:", light, ",contrast:", contrast)
result = cv.addWeighted(image, contrast, blank, 0, light)
cv.imshow("result", result)
cv.addWeighter(src1, alpha, src2, beta, gamma, dst=None, dtype=None)
- src1:第一个原数组
- alpha,第一个数组元素权重
- src2第二个原数组
- beta,第二个数组元素权重
- gamma,图1与图2作和后添加的数值。不要太大,不然图片一片白。总和等于255以上就是纯白色了
- dst,输出图片
键盘响应操作
def keys_demo():
image = cv.imread("D:/Code/1.jpg") # (666, 999, 3)
cv.namedWindow("input", cv.WINDOW_AUTOSIZE) # 创建窗口 (窗口名,窗口大小自适应图片大小并且不能更改)
cv.imshow("input", image)
while True:
c = cv.waitKey(1) # 等待用户触发事件时间
if c == 49: # 按键1
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
cv.imshow("result", gray)
if c == 50: # 按键2
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
cv.imshow("result", hsv)
if c == 27: # 如果按下ESC(ASCII码为27)
cv.destroyAllWindows()
OpenCV自带颜色表操作
def color_table_demo():
colormap = [
cv.COLORMAP_AUTUMN,
cv.COLORMAP_BONE,
cv.COLORMAP_JET,
cv.COLORMAP_WINTER,
cv.COLORMAP_RAINBOW,
cv.COLORMAP_OCEAN,
cv.COLORMAP_SUMMER,
cv.COLORMAP_SPRING,
cv.COLORMAP_COOL,
cv.COLORMAP_PINK,
cv.COLORMAP_HOT,
cv.COLORMAP_PARULA,
cv.COLORMAP_MAGMA,
cv.COLORMAP_INFERNO,
cv.COLORMAP_PLASMA,
cv.COLORMAP_VIRIDIS,
cv.COLORMAP_CIVIDIS,
cv.COLORMAP_TWILIGHT,
cv.COLORMAP_TWILIGHT_SHIFTED]
image = cv.imread("D:/Code/1.jpg") # (666, 999, 3)
cv.namedWindow("input", cv.WINDOW_AUTOSIZE) # 创建窗口 (窗口名,窗口大小自适应图片大小并且不能更改)
cv.imshow("input", image)
index = 0
while True:
dst = cv.applyColorMap(image, colormap[index % 19])
index += 1
cv.imshow("result", dst)
c = cv.waitKey(200) # 等待用户触发事件时间
if c == 27: # 如果按下ESC(ASCII码为27)
break
cv.destroyAllWindows()
图像像素的逻辑操作
def bitwise_demo():
b1 = np.zeros((400, 400, 3), dtype=np.uint8)
b1[:, :] = (255, 0, 255)
b2 = np.zeros((400, 400, 3), dtype=np.uint8)
b2[:, :] = (0, 255, 255)
cv.imshow("b1", b1)
cv.imshow("b2", b2)
dst1 = cv.bitwise_and(b1, b2) # 与运算
dst2 = cv.bitwise_or(b1, b2) # 或运算
cv.imshow("bitwise_and", dst1)
cv.imshow("bitwise_or", dst2)
cv.waitKey(0)
通道分离与合并
def channels_split_demo():
b1 = cv.imread("D:/Code/1.jpg")
print(b1.shape)
cv.imshow("input", b1)
cv.imshow("b1", b1[:, :, 2])
mv = cv.split(b1)
mv[0][:, :] = 255 # 将第一通道的值都改为255
result = cv.merge(mv) # 将第一通道合并到图像中
cv.imshow("result", result)
cv.waitKey(0)
cv.destroyAllWindows()
图像色彩空间转换
def color_space_demo():
b1 = cv.imread("src/1.jpg")
print(b1.shape)
cv.imshow("input", b1)
hsv = cv.cvtColor(b1, cv.COLOR_BGR2HSV)
print(hsv)
cv.imshow("hsv", hsv)
mask = cv.inRange(hsv, (0, 30, 46), (25, 255, 255)) # 将图像中颜色在第二个参数和第三个参数范围内的颜色设为0,其余为1
# cv.bitwise_not(mask, mask) # 自身取反
result = cv.bitwise_and(b1, b1, mask=mask) # mask:指定操作范围
cv.imshow("mask", mask)
cv.imshow("result", result)
cv.waitKey(0)
cv.destroyAllWindows()
cv.inRange(src, lowerb, upperb, dst=None)
- src:图片
- lowerb:图像中低于lowerb的值,图像值变为0
- upperb:是图像中高于upperb的值,图像值变为0
图像像素值统计
def pixel_stat_demo():
# b1 = cv.imread("src/1.jpg")
b1 = np.zeros((512, 512, 3), dtype=np.uint8)
print(b1.shape)
cv.imshow("input", b1)
means, dev = cv.meanStdDev(b1) # 均值,方差
print("means:", means, "dev:", dev)
cv.waitKey(0)
cv.destroyAllWindows()
图像几何形状绘制
def drawing_demo():
b1 = np.zeros((512, 512, 3), dtype=np.uint8)
cv.rectangle(b1, (50, 50), (400, 400), (0, 0, 255), 2, 8, 0)
cv.circle(b1, (225, 225), 175, (255, 0, 0), -1, 8, 0)
cv.line(b1, (50, 50), (400, 400), (0, 255, 0), 2, 8, 0)
# b1[:,:] = 0
cv.putText(b1, "This is a text", (50, 50), cv.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 255), 2, 8)
cv.imshow("result", b1)
cv.waitKey(0)
cv.destroyAllWindows()
cv.rectangle(img, pt1, pt2, color, thickness=None, lineType=None, shift=None)
- img:所绘制的图片
- pt1:矩形的左上角坐标
- pt2:矩形的右下角坐标
- color:矩形颜色(bgr)
- thickness:线条粗细,-1时为填充
- lineType:
- shift:点坐标中的分数位的偏移数
cv.circle(img, center, radius, color, thickness=None, lineType=None, shift=None)
- img:所绘制的图片
- center:圆心坐标
- radius:半径
- color:颜色(bgr)
- thickness:线条粗细,-1时为填充
- lineType:
- shift:点坐标中的分数位的偏移数
cv.line(img, pt1, pt2, color, thickness=None, lineType=None, shift=None)
- img:所绘制的图片
- pt1:起点坐标
- pt2:终点坐标
- color:颜色(bgr)
- thickness:线条粗细,不能取负值
- lineType:
- shift:点坐标中的分数位的偏移数
cv.putText(img, text, org, fontFace, fontScale, color, thickness=None, lineType=None, bottomLeftOrigin=None)
- img:所绘制的图片
- text:文本内容
- org:文本左上角坐标
- fontFace:字体
- fontScale:字号
- thickness:线条粗细,不能取负值
- lineType:
- bottomLeftOrigin:如果为true,则图像数据原点位于左下角。 否则它位于左上角
随机数与随机颜色
def random_color_demo():
b1 = np.zeros((512, 512, 3), dtype=np.uint8)
while True:
xx = np.random.randint(0, 512, 2, dtype=np.int)
yy = np.random.randint(0, 512, 2, dtype=np.int)
bgr = np.random.randint(0, 255, 3, dtype=np.int32)
cv.line(b1, (xx[0], yy[0]), (xx[1], yy[1]), (np.int(bgr[0]), np.int(bgr[1]), np.int(bgr[2])), 1, 8, 0)
cv.imshow("result", b1)
c = cv.waitKey(1)
if c == 27:
break
cv.destroyAllWindows()
np.random.randint(low, high=None, size=None, dtype=None)
- low:最小值
- high:最大值
- size:生成随机数的数量
- dtype:随机数类型
多边形填充与绘制
def polyline_drawing_demo():
canvas = np.zeros((512, 512, 3), dtype=np.uint8)
pts = np.array([[100, 100], [300, 100], [450, 200], [320, 450], [80, 400]])
# cv.fillPoly(canvas, [pts], (255, 0, 255), 8, 0)
# cv.polylines(canvas, [pts], True, (0, 0, 255), 2, 8, 0)
cv.drawContours(canvas, [pts], -1, (255, 0, 0), -1) # 可实现前两个函数功能,最后一个参数为-1时填充,正数时不填充
函数中的[pts]是因为可以同时绘制多组点,所以在函数中以数组形式作为参数,如需绘制多点,则参数为[pts1, pts2, pts3, …]
鼠标操作与响应
b1 = cv.imread("D:/Code/py/OpenCV/src/1.jpg")
img = np.copy(b1)
x1 = -1
x2 = -1
y1 = -1
y2 = -1
def mouse_drawing(event, x, y, flags, param):
global x1, x2, y1, y2
if event == cv.EVENT_LBUTTONDOWN:
x1 = x
y1 = y
if event == cv.EVENT_MOUSEMOVE:
if x1 < 0 or y1 < 0:
return
x2 = x
y2 = y
b1[:, :, :] = img[:, :, :]
cv.rectangle(b1, (x1, y1), (x2, y2), (0, 0, 255), 2, 8, 0)
if event == cv.EVENT_LBUTTONUP:
if x1 < 0 or y1 < 0:
return
x2 = x
y2 = y
b1[:, :, :] = img[:, :, :]
cv.rectangle(b1, (x1, y1), (x2, y2), (0, 0, 255), 2, 8, 0)
x1 = -1
x2 = -1
y1 = -1
y2 = -1
def mouse_demo():
cv.namedWindow("mouse_demo", cv.WINDOW_AUTOSIZE)
cv.setMouseCallback("mouse_demo", mouse_drawing)
while True:
cv.imshow("mouse_demo", b1)
c = cv.waitKey(1)
if c == 27:
break
cv.destroyAllWindows()
图像像素类型转换与归一化
def norm_demo():
image = cv.imread("D:/Code/py/OpenCV/src/1.jpg")
cv.namedWindow("norm_demo", cv.WINDOW_AUTOSIZE)
result = np.zeros_like(np.float32(image)) # 将图片转化为浮点型
cv.normalize(np.float32(image), result, 0, 1, cv.NORM_MINMAX, dtype=cv.CV_32F) # 第二种方法将图片转换为浮点型
cv.imshow("norm_demo", np.uint8(result * 255)) # 将图片数据类型还原
cv.waitKey(0)
cv.destroyAllWindows()
为什么需要将图片像素类型转为浮点
例如在深度学习当中,需要大量的浮点运算,所以将图片像素类型也转为浮点后可进行更精准的计算
图像缩放与差值
def resize_demo():
image = cv.imread("D:/Code/py/OpenCV/src/1.jpg")
h, w, c = image.shape
cv.namedWindow("resize", cv.WINDOW_AUTOSIZE)
dst = cv.resize(image, (0, 0), fx=0.75, fy=0.5, interpolation=cv.INTER_NEAREST)
cv.imshow("resize", dst)
cv.waitKey(0)
cv.destroyAllWindows()
cv.resize(src, dsize, dst=None, fx=None, fy=None, interpolation=None)
- src:需要进行缩放的图像
- dsize:需要缩放到的尺寸(h,w)只能为整数,如果为(0,0),则可以指定fx和fy参数进行倍数缩放
- fx:图像宽的缩放倍数
- fy:图像高的缩放倍数
- interpolation:图像缩放算法
INTER_NEAREST - 最邻近插值
INTER_LINEAR - 双线性插值,如果最后一个参数你不指定,默认使用这种方法
INTER_AREA - resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire’-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method.
INTER_CUBIC - 4x4像素邻域内的双立方插值
INTER_LANCZOS4 - 8x8像素邻域内的Lanczos插值
图像翻转
def flip_demo():
image = cv.imread("D:/Code/py/OpenCV/src/1.jpg")
cv.imshow("image", image)
cv.namedWindow("flip", cv.WINDOW_AUTOSIZE)
dst = cv.flip(image, 0)
cv.imshow("flip", dst)
cv.waitKey(0)
cv.destroyAllWindows()
cv.flip(src, flipCode, dst=None)
- src:输入图像
- flipCode:翻转形式
-1:水平,垂直方向同时翻转
0:垂直方向翻转
1:水平方向翻转
图像旋转
相关文章
def rotate_demo():
src = cv.imread("D:/Code/py/OpenCV/src/1.jpg")
h, w, c = src.shape
M = np.zeros((2, 3), dtype=np.float32)
alpha = np.cos(np.pi / 4.0)
beta = np.sin(np.pi / 4.0)
print("alpha : ", alpha)
# 初始旋转矩阵
M[0, 0] = alpha
M[1, 1] = alpha
M[0, 1] = beta
M[1, 0] = -beta
cx = w / 2
cy = h / 2
tx = (1 - alpha) * cx - beta * cy
ty = beta * cx + (1 - alpha) * cy
M[0, 2] = tx
M[1, 2] = ty
# change with full size
bound_w = int(h * np.abs(beta) + w * np.abs(alpha))
bound_h = int(h * np.abs(alpha) + w * np.abs(beta))
# 添加中心位置迁移
M[0, 2] += bound_w / 2 - cx
M[1, 2] += bound_h / 2 - cy
dst = cv.warpAffine(src, M, (bound_w, bound_h))
cv.imshow("rotate without cropping", dst)
cv.waitKey(0)
cv.destroyAllWindows()
视频文件/摄像头使用
def video_demo():
cap = cv.VideoCapture(0)
w = cap.get(cv.CAP_PROP_FRAME_WIDTH) # 获取视频的宽
h = cap.get(cv.CAP_PROP_FRAME_HEIGHT) # 获取视频的高
fps = cap.get(cv.CAP_PROP_FPS) # 获取视频的帧数
print(w, h, fps)
while True:
ret, frame = cap.read()
frame = cv.flip(frame,1)
if ret is True:
cv.imshow("frame", frame)
c = cv.waitKey(10) # 读取视频时,等待时间决定播放的快慢
if c == 27:
break
cv.destroyAllWindows()
cv.VideoCapture()
- 参数为数字,调用系统摄像头,数字表示为摄像头编号
- 参数为路径,表示读取视频文件
图像直方图
import matplotlib.pyplot as plt # 需要导入matplotliib库作图
def image_hist():
image = cv.imread("D:/Code/py/OpenCV/src/1.jpg")
cv.imshow("image", image)
color = ("blue", "green", "red")
for i, color in enumerate(color):
hist = cv.calcHist([image], [i], None, [256], [0, 256])
print(hist)
plt.plot(hist, color=color)
plt.xlim([0, 256])
plt.show()
cv.waitKey(0)
cv.destroyAllWindows()
cv.calcHist(images, channels, mask, histSize, ranges, hist=None, accumulate=None)
- images:输入的图像,需要用[]括起来
- channels:计算直方图的通道
- mask:遮罩,None为处理整张图像
- histSize:表示直方图被分成多少份,就是多少个柱
- ranges:直方图中各个像素的值
二维直方图
def hist2d_demo():
image = cv.imread("D:/Code/py/OpenCV/src/1.jpg")
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
hist = cv.calcHist([hsv], [0, 1], None, [48, 48], [0, 180, 0, 256])
dst = cv.resize(hist, (400, 400))
cv.normalize(dst, dst, 0, 255, cv.NORM_MINMAX)
cv.imshow("image", image)
dst = cv.applyColorMap(np.uint8(dst), cv.COLORMAP_JET)
cv.imshow("hist", dst)
plt.imshow(hist, interpolation='nearest')
plt.title("2D Histogram")
plt.show()
cv.waitKey(0)
cv.destroyAllWindows()