OpenCV 入门讲解

图像基础处理

1.图片显示

用 imread 显示图像

# 加载图像(如果图像加载失败,那么返回的对象img为None)
# 第一个参数:filename,给定图片路径参数
# 第二个参数:flags,指定图像的读取方式;默认是使用BGR模型加载图像,参考:
# https://docs.opencv.org/3.4.0/d4/da8/group__imgcodecs.html#gga61d9b0126a3e57d9277ac48327799c80af660544735200cbe942eea09232eb822
# 当设置为0表示灰度图像加载,1表示加载BGR图像, 默认为1,-1表示加载alpha透明通道的图像。
img = cv.imread('xiaoren.png', 0)
print(np.shape(img))

# 图像可视化
cv.imshow('image', img)
# 让图像暂停delay毫秒,当delay秒设置为0的时候,表示永远; 当键盘任意输入的时候,结束暂停
cv.waitKey(0)
# 释放所有资源
cv.destroyAllWindows()


# 明确给定窗口资源
cv.namedWindow('image', cv.WINDOW_NORMAL)
# 图像可视化
cv.imshow('image', img)
# 让图像暂停delay毫秒,当delay秒设置为0的时候,表示永远,当键盘任意输入的时候,结束暂停
cv.waitKey(0)
# 释放指定窗口资源
cv.destroyWindow('image')


# 图像保存
# 第一个参数是图像名称,第二个参数就是图像对象
cv.imwrite('t1.png', img)

# 根据不同的输入进行图像的操作
cv.imshow('image', img)
# 等待键盘的输入(键盘上各个键对应ASCII码, http://ascii.911cha.com/)
k = cv.waitKey(0) & 0xFF

if k == 27:
    print(k)
    # 当输入的是ESC退出键的时候
    cv.destroyAllWindows()
else:
    # 当输入的是其他键的时候
    cv.imwrite('t2.png', img)
    cv.destroyAllWindows()


# 读取图像将图像转换为Matplotlib可视化
# NOTE: 如果需要可视化图像,需要注意:OpenCV中是BGR图像,而Matplotlib中是RGB的图像。
img = cv.imread('t1.png', cv.IMREAD_GRAYSCALE)
plt.imshow(img, cmap='gray')
plt.show()

# 读取图像将图像转换为Matplotlib可视化
# NOTE: 如果需要可视化图像,需要注意:OpenCV中是BGR图像,而Matplotlib中是RGB的图像。
img = cv.imread('t1.png', 1)
img2 = np.zeros_like(img, dtype=img.dtype)
img2[:, :, 0] = img[:, :, 2]
img2[:, :, 1] = img[:, :, 1]
img2[:, :, 2] = img[:, :, 0]
print(img2.shape)
print(img2)
plt.imshow(img2)
plt.show()

img = cv.imread('t1.png', 1)
img1 = transpose(img, (2,1,0))
# 这个transpose的操作实际上更改维度顺序,也就是将img的[600,510,3]这个形状转换为[3,510,600]

视频基本处理

# 从摄像机获取视频
# 创建一个基于摄像头的视频读取流,给定基于第一个视频设备
capture = cv.VideoCapture(0)

# 设置摄像头相关参数(但是实际参数会进行稍微的偏移)
success=capture.set(cv.CAP_PROP_FRAME_WIDTH, 880)
if success:
    print("设置宽度成功")
success=capture.set(cv.CAP_PROP_FRAME_HEIGHT, 480)
if success:
    print("设置高度成功")

# 打印属性
size = (int(capture.get(cv.CAP_PROP_FRAME_WIDTH)),
        int(capture.get(cv.CAP_PROP_FRAME_HEIGHT)))
print(size)

# 遍历获取视频中的图像
# 读取当前时刻的摄像头捕获的图像, 返回为值:True/False, Image/None
success, frame = capture.read()
# 遍历以及等待任意键盘输入(-1表示等待delay后,没有任何键盘输入)
while success and cv.waitKey(1) == -1:
    cv.imshow('frame', frame)
    # 读取下一帧的图像
    success, frame = capture.read()

# 释放资源
capture.release()
cv.destroyAllWindows()
打印:
设置宽度成功
设置高度成功
(848, 480)
 
# 保存摄像机的视频流
# 创建一个基于摄像头的视频读取流,给定基于第一个视频设备
capture = cv.VideoCapture(0)

# 设置摄像头相关参数(但是实际参数会进行稍微的偏移)
success=capture.set(cv.CAP_PROP_FRAME_WIDTH, 880)
if success:
    print("设置宽度成功")
success=capture.set(cv.CAP_PROP_FRAME_HEIGHT, 480)
if success:
    print("设置高度成功")

# 打印属性
size = (int(capture.get(cv.CAP_PROP_FRAME_WIDTH)),
        int(capture.get(cv.CAP_PROP_FRAME_HEIGHT)))
print(size)
# 此时摄像头的帧率(摄像头图像数据没有产生,没办法指导帧率)
print(capture.get(cv.CAP_PROP_FPS))

# 创建一个视频输出对象
# 设置视频中的帧率,也就是每秒存在多少张图片
fps = 15
video_writer = cv.VideoWriter('v1.avi', cv.VideoWriter_fourcc('I', '4', '2', '0'),
                               fps, size)

# 构建10秒的图像输出
num_frames_remaining = 10 * fps - 1
success, frame = capture.read()
while success and num_frames_remaining > 0:
    video_writer.write(frame)
    success, frame = capture.read()
    num_frames_remaining -= 1

# 释放资源
capture.release()
cv.destroyAllWindows()

# 视频文件读入
# 创建一个基于文件的视频读取流,给定基于第一个视频设备
capture = cv.VideoCapture("v1.avi")

# 打印属性
size = (int(capture.get(cv.CAP_PROP_FRAME_WIDTH)),
        int(capture.get(cv.CAP_PROP_FRAME_HEIGHT)))
print(size)
# print(capture.get(cv.CAP_PROP_FPS))

# 遍历获取视频中的图像
# 读取当前时刻的摄像头捕获的图像, 返回为值:True/False, Image/None
success, frame = capture.read()
# 遍历以及等待任意键盘输入
while success and cv.waitKey(60) == -1:
    cv.imshow('frame', frame)
    # 读取下一帧的图像
    success, frame = capture.read()

# 释放资源
capture.release()
cv.destroyAllWindows()

# 视频文件读入
# 创建一个基于文件的视频读取流,给定基于第一个视频设备
capture = cv.VideoCapture("v1.avi")

# 打印属性
size = (int(capture.get(cv.CAP_PROP_FRAME_WIDTH)),
        int(capture.get(cv.CAP_PROP_FRAME_HEIGHT)))
print(size)
# print(capture.get(cv.CAP_PROP_FPS))

# 遍历获取视频中的图像
# 读取当前时刻的摄像头捕获的图像, 返回为值:True/False, Image/None
success, frame = capture.read()
# 遍历以及等待任意键盘输入
k = 0
while success and cv.waitKey(60) == -1:
#     cv.imshow('frame', frame)
    # 读取下一帧的图像
    success, frame = capture.read()
    # 输出文件夹必须存在
    cv.imwrite('./v1_frame/img_{}.png'.format(k), frame)
    k += 1

# 释放资源
capture.release()
cv.destroyAllWindows()

基于OpenCV的基本绘画

主要是在OpenCV的Image对象上进行绘画,主要方法如下:cv.line画直线、cv.circle画圆、cv.rectangle画矩形、cv.ellipse画椭圆、cv.putText画文字等;常见参数如下所示:

·img:给定绘画的对象
·color:给定像素点的颜色
·thickness:给定线条粗细程度,-1表示填充图像
·lineType:给定线条的类型

# 创建一个黑色的图像(BGR格式)
img = np.zeros((512,512,3), np.uint8)

# 画一条直线
cv.line(img, pt1=(0,0), pt2=(511,511), color=(255,0,0), thickness=5)

# 可视化
cv.imshow('image', img)

cv.waitKey(0)
# 释放指定窗口资源
cv.destroyWindow('image')

# 创建一个黑色的图像(BGR格式)
img = np.zeros((512,512,3), np.uint8)

# 画一条矩形,给定左上角的点以及右下角的点
# 点坐标的形状为: [宽度,高度]
cv.rectangle(img, pt1=(10,10), pt2=(50,320), color=(255,0,0), thickness=5)

# 可视化
cv.imshow('image', img)

cv.waitKey(0)
# 释放指定窗口资源
cv.destroyWindow('image')

# 创建一个黑色的图像(BGR格式)
img = np.zeros((512,512,3), np.uint8)

# 画一条园,给定中心点和半径
cv.circle(img, center=(200,200), radius=100, color=(0,0,255), thickness=1)

# 可视化
cv.imshow('image', img)

cv.waitKey(0)
# 释放指定窗口资源
cv.destroyWindow('image')


# 创建一个黑色的图像(BGR格式)
img = np.zeros((512,512,3), np.uint8)

# 画一条椭圆,给定椭圆的圆心、轴长、偏移的角度、以及椭圆的角度信息
cv.ellipse(img, center=(210,310), axes=(100,50), angle=0, startAngle=0, endAngle=180,
           color=(255,0,0), thickness=5)
cv.ellipse(img, center=(110,110), axes=(100,50), angle=30, startAngle=0, endAngle=180,
           color=(0,255,0), thickness=5)
cv.ellipse(img, center=(310,110), axes=(10,50), angle=0, startAngle=0, endAngle=360,
           color=(0,0,255), thickness=-1)
cv.ellipse(img, center=(210,210), axes=(50,50), angle=0, startAngle=0, endAngle=180,
           color=(0,0,255), thickness=-1)
cv.ellipse(img, center=(410,410), axes=(50,50), angle=0, startAngle=0, endAngle=180,
           color=(0,0,255), thickness=2)
cv.rectangle(img, pt1=(360,410), pt2=(460,410), color=(0,0,255), thickness=2)


# 可视化
cv.imshow('image', img)

cv.waitKey(0)
# 释放指定窗口资源
cv.destroyWindow('image')

# 创建一个黑色的图像(BGR格式)
img = np.zeros((512,512,3), np.uint8)

# 画多边形
pts = np.array([[10,5], [20,50], [70,80],[50,10]], np.int32)
pts = pts.reshape((-1,1,2))
print(pts.shape)
cv.polylines(img, [pts], isClosed=False, color=(255,0,0), thickness=5)

# 可视化
cv.imshow('image', img)

cv.waitKey(0)
# 释放指定窗口资源
cv.destroyWindow('image')

# 创建一个黑色的图像(BGR格式)
img = np.zeros((512,512,3), np.uint8)

# 添加文本
font = cv.FONT_HERSHEY_SIMPLEX
cv.putText(img, text='OpenCV', org=(10,450), fontFace=font,
           fontScale=4, color=(255,255,255), thickness=2, lineType=cv.LINE_AA)

# 可视化
cv.imshow('image', img)

cv.waitKey(0)
# 释放指定窗口资源
cv.destroyWindow('image')

更改颜色空间

# 获取所有的颜色通道(以COLOR_开头的属性)
# 在OpenCV中HSV颜色空间的取值范围为:H->[0,179], S->[0,255], V->[0,255]; 其它图像处理软件不一样
flags = [i for i in dir(cv) if i.startswith('COLOR_')]
print("总颜色转换方式:{}".format(len(flags)))
print(flags)

打印:
总颜色转换方式:274
['COLOR_BAYER_BG2BGR', 'COLOR_BAYER_BG2BGRA', 'COLOR_BAYER_BG2BGR_EA', 'COLOR_BAYER_BG2BGR_VNG', 'COLOR_BAYER_BG2GRAY', 'COLOR_BAYER_BG2RGB', 'COLOR_BAYER_BG2RGBA', 'COLOR_BAYER_BG2RGB_EA', 'COLOR_BAYER_BG2RGB_VNG', 'COLOR_BAYER_GB2BGR', 'COLOR_BAYER_GB2BGRA', 'COLOR_BAYER_GB2BGR_EA', 'COLOR_BAYER_GB2BGR_VNG', 'COLOR_BAYER_GB2GRAY', 'COLOR_BAYER_GB2RGB', 'COLOR_BAYER_GB2RGBA', 'COLOR_BAYER_GB2RGB_EA', 'COLOR_BAYER_GB2RGB_VNG', 'COLOR_BAYER_GR2BGR', 'COLOR_BAYER_GR2BGRA', 'COLOR_BAYER_GR2BGR_EA', 'COLOR_BAYER_GR2BGR_VNG', 'COLOR_BAYER_GR2GRAY', 'COLOR_BAYER_GR2RGB', 'COLOR_BAYER_GR2RGBA', 'COLOR_BAYER_GR2RGB_EA', 'COLOR_BAYER_GR2RGB_VNG', 'COLOR_BAYER_RG2BGR', 'COLOR_BAYER_RG2BGRA', 'COLOR_BAYER_RG2BGR_EA', 'COLOR_BAYER_RG2BGR_VNG', 'COLOR_BAYER_RG2GRAY', 'COLOR_BAYER_RG2RGB', 'COLOR_BAYER_RG2RGBA', 'COLOR_BAYER_RG2RGB_EA', 'COLOR_BAYER_RG2RGB_VNG', 'COLOR_BGR2BGR555', 'COLOR_BGR2BGR565', 'COLOR_BGR2BGRA', 'COLOR_BGR2GRAY', 'COLOR_BGR2HLS', 'COLOR_BGR2HLS_FULL', 'COLOR_BGR2HSV', 'COLOR_BGR2HSV_FULL', 'COLOR_BGR2LAB', 'COLOR_BGR2LUV', 'COLOR_BGR2Lab', 'COLOR_BGR2Luv', 'COLOR_BGR2RGB', 'COLOR_BGR2RGBA', 'COLOR_BGR2XYZ', 'COLOR_BGR2YCR_CB', 'COLOR_BGR2YCrCb', 'COLOR_BGR2YUV', 'COLOR_BGR2YUV_I420', 'COLOR_BGR2YUV_IYUV', 'COLOR_BGR2YUV_YV12', 'COLOR_BGR5552BGR', 'COLOR_BGR5552BGRA', 'COLOR_BGR5552GRAY', 'COLOR_BGR5552RGB', 'COLOR_BGR5552RGBA', 'COLOR_BGR5652BGR', 'COLOR_BGR5652BGRA', 'COLOR_BGR5652GRAY', 'COLOR_BGR5652RGB', 'COLOR_BGR5652RGBA', 'COLOR_BGRA2BGR', 'COLOR_BGRA2BGR555', 'COLOR_BGRA2BGR565', 'COLOR_BGRA2GRAY', 'COLOR_BGRA2RGB', 'COLOR_BGRA2RGBA', 'COLOR_BGRA2YUV_I420', 'COLOR_BGRA2YUV_IYUV', 'COLOR_BGRA2YUV_YV12', 'COLOR_BayerBG2BGR', 'COLOR_BayerBG2BGRA', 'COLOR_BayerBG2BGR_EA', 'COLOR_BayerBG2BGR_VNG', 'COLOR_BayerBG2GRAY', 'COLOR_BayerBG2RGB', 'COLOR_BayerBG2RGBA', 'COLOR_BayerBG2RGB_EA', 'COLOR_BayerBG2RGB_VNG', 'COLOR_BayerGB2BGR', 'COLOR_BayerGB2BGRA', 'COLOR_BayerGB2BGR_EA', 'COLOR_BayerGB2BGR_VNG', 'COLOR_BayerGB2GRAY', 'COLOR_BayerGB2RGB', 'COLOR_BayerGB2RGBA', 'COLOR_BayerGB2RGB_EA', 'COLOR_BayerGB2RGB_VNG', 'COLOR_BayerGR2BGR', 'COLOR_BayerGR2BGRA', 'COLOR_BayerGR2BGR_EA', 'COLOR_BayerGR2BGR_VNG', 'COLOR_BayerGR2GRAY', 'COLOR_BayerGR2RGB', 'COLOR_BayerGR2RGBA', 'COLOR_BayerGR2RGB_EA', 'COLOR_BayerGR2RGB_VNG', 'COLOR_BayerRG2BGR', 'COLOR_BayerRG2BGRA', 'COLOR_BayerRG2BGR_EA', 'COLOR_BayerRG2BGR_VNG', 'COLOR_BayerRG2GRAY', 'COLOR_BayerRG2RGB', 'COLOR_BayerRG2RGBA', 'COLOR_BayerRG2RGB_EA', 'COLOR_BayerRG2RGB_VNG', 'COLOR_COLORCVT_MAX', 'COLOR_GRAY2BGR', 'COLOR_GRAY2BGR555', 'COLOR_GRAY2BGR565', 'COLOR_GRAY2BGRA', 'COLOR_GRAY2RGB', 'COLOR_GRAY2RGBA', 'COLOR_HLS2BGR', 'COLOR_HLS2BGR_FULL', 'COLOR_HLS2RGB', 'COLOR_HLS2RGB_FULL', 'COLOR_HSV2BGR', 'COLOR_HSV2BGR_FULL', 'COLOR_HSV2RGB', 'COLOR_HSV2RGB_FULL', 'COLOR_LAB2BGR', 'COLOR_LAB2LBGR', 'COLOR_LAB2LRGB', 'COLOR_LAB2RGB', 'COLOR_LBGR2LAB', 'COLOR_LBGR2LUV', 'COLOR_LBGR2Lab', 'COLOR_LBGR2Luv', 'COLOR_LRGB2LAB', 'COLOR_LRGB2LUV', 'COLOR_LRGB2Lab', 'COLOR_LRGB2Luv', 'COLOR_LUV2BGR', 'COLOR_LUV2LBGR', 'COLOR_LUV2LRGB', 'COLOR_LUV2RGB', 'COLOR_Lab2BGR', 'COLOR_Lab2LBGR', 'COLOR_Lab2LRGB', 'COLOR_Lab2RGB', 'COLOR_Luv2BGR', 'COLOR_Luv2LBGR', 'COLOR_Luv2LRGB', 'COLOR_Luv2RGB', 'COLOR_M_RGBA2RGBA', 'COLOR_RGB2BGR', 'COLOR_RGB2BGR555', 'COLOR_RGB2BGR565', 'COLOR_RGB2BGRA', 'COLOR_RGB2GRAY', 'COLOR_RGB2HLS', 'COLOR_RGB2HLS_FULL', 'COLOR_RGB2HSV', 'COLOR_RGB2HSV_FULL', 'COLOR_RGB2LAB', 'COLOR_RGB2LUV', 'COLOR_RGB2Lab', 'COLOR_RGB2Luv', 'COLOR_RGB2RGBA', 'COLOR_RGB2XYZ', 'COLOR_RGB2YCR_CB', 'COLOR_RGB2YCrCb', 'COLOR_RGB2YUV', 'COLOR_RGB2YUV_I420', 'COLOR_RGB2YUV_IYUV', 'COLOR_RGB2YUV_YV12', 'COLOR_RGBA2BGR', 'COLOR_RGBA2BGR555', 'COLOR_RGBA2BGR565', 'COLOR_RGBA2BGRA', 'COLOR_RGBA2GRAY', 'COLOR_RGBA2M_RGBA', 'COLOR_RGBA2RGB', 'COLOR_RGBA2YUV_I420', 'COLOR_RGBA2YUV_IYUV', 'COLOR_RGBA2YUV_YV12', 'COLOR_RGBA2mRGBA', 'COLOR_XYZ2BGR', 'COLOR_XYZ2RGB', 'COLOR_YCR_CB2BGR', 'COLOR_YCR_CB2RGB', 'COLOR_YCrCb2BGR', 'COLOR_YCrCb2RGB', 'COLOR_YUV2BGR', 'COLOR_YUV2BGRA_I420', 'COLOR_YUV2BGRA_IYUV', 'COLOR_YUV2BGRA_NV12', 'COLOR_YUV2BGRA_NV21', 'COLOR_YUV2BGRA_UYNV', 'COLOR_YUV2BGRA_UYVY', 'COLOR_YUV2BGRA_Y422', 'COLOR_YUV2BGRA_YUNV', 'COLOR_YUV2BGRA_YUY2', 'COLOR_YUV2BGRA_YUYV', 'COLOR_YUV2BGRA_YV12', 'COLOR_YUV2BGRA_YVYU', 'COLOR_YUV2BGR_I420', 'COLOR_YUV2BGR_IYUV', 'COLOR_YUV2BGR_NV12', 'COLOR_YUV2BGR_NV21', 'COLOR_YUV2BGR_UYNV', 'COLOR_YUV2BGR_UYVY', 'COLOR_YUV2BGR_Y422', 'COLOR_YUV2BGR_YUNV', 'COLOR_YUV2BGR_YUY2', 'COLOR_YUV2BGR_YUYV', 'COLOR_YUV2BGR_YV12', 'COLOR_YUV2BGR_YVYU', 'COLOR_YUV2GRAY_420', 'COLOR_YUV2GRAY_I420', 'COLOR_YUV2GRAY_IYUV', 'COLOR_YUV2GRAY_NV12', 'COLOR_YUV2GRAY_NV21', 'COLOR_YUV2GRAY_UYNV', 'COLOR_YUV2GRAY_UYVY', 'COLOR_YUV2GRAY_Y422', 'COLOR_YUV2GRAY_YUNV', 'COLOR_YUV2GRAY_YUY2', 'COLOR_YUV2GRAY_YUYV', 'COLOR_YUV2GRAY_YV12', 'COLOR_YUV2GRAY_YVYU', 'COLOR_YUV2RGB', 'COLOR_YUV2RGBA_I420', 'COLOR_YUV2RGBA_IYUV', 'COLOR_YUV2RGBA_NV12', 'COLOR_YUV2RGBA_NV21', 'COLOR_YUV2RGBA_UYNV', 'COLOR_YUV2RGBA_UYVY', 'COLOR_YUV2RGBA_Y422', 'COLOR_YUV2RGBA_YUNV', 'COLOR_YUV2RGBA_YUY2', 'COLOR_YUV2RGBA_YUYV', 'COLOR_YUV2RGBA_YV12', 'COLOR_YUV2RGBA_YVYU', 'COLOR_YUV2RGB_I420', 'COLOR_YUV2RGB_IYUV', 'COLOR_YUV2RGB_NV12', 'COLOR_YUV2RGB_NV21', 'COLOR_YUV2RGB_UYNV', 'COLOR_YUV2RGB_UYVY', 'COLOR_YUV2RGB_Y422', 'COLOR_YUV2RGB_YUNV', 'COLOR_YUV2RGB_YUY2', 'COLOR_YUV2RGB_YUYV', 'COLOR_YUV2RGB_YV12', 'COLOR_YUV2RGB_YVYU', 'COLOR_YUV420P2BGR', 'COLOR_YUV420P2BGRA', 'COLOR_YUV420P2GRAY', 'COLOR_YUV420P2RGB', 'COLOR_YUV420P2RGBA', 'COLOR_YUV420SP2BGR', 'COLOR_YUV420SP2BGRA', 'COLOR_YUV420SP2GRAY', 'COLOR_YUV420SP2RGB', 'COLOR_YUV420SP2RGBA', 'COLOR_YUV420p2BGR', 'COLOR_YUV420p2BGRA', 'COLOR_YUV420p2GRAY', 'COLOR_YUV420p2RGB', 'COLOR_YUV420p2RGBA', 'COLOR_YUV420sp2BGR', 'COLOR_YUV420sp2BGRA', 'COLOR_YUV420sp2GRAY', 'COLOR_YUV420sp2RGB', 'COLOR_YUV420sp2RGBA', 'COLOR_mRGBA2RGBA']

转换颜色空间

# 加载数据
img = cv.imread('opencv-logo.png')

# 转换为HSV格式
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)

# 图像可视化
cv.imshow('image', hsv)
cv.waitKey(0)
cv.destroyAllWindows()

大小重置

# 加载图像
img = cv.imread("xiaoren.png")

old_height, old_width, _ = img.shape
print("旧图像的大小, 高度={}, 宽度:{}".format(old_height, old_width))
new_height = int(0.8 * old_height)
new_width = 250
print("新图像的大小, 高度={}, 宽度:{}".format(new_height, new_width))
dst = cv.resize(img, (new_width, new_height))
print(dst.shape)

# 图像可视化
cv.imshow('mask', dst)
cv.waitKey(0)
cv.destroyAllWindows()

图像平移

# 构建一个M
M = np.float32([
    [1, 0, -10], 
    [0, 1, 10]
])
# warpAffine计算规则:dst(x,y)=src(m11*x+m12*y+m13, m21*x+m22*y+m23)
# x和y是坐标点
dst = cv.warpAffine(img, M, (img.shape[1], img.shape[0]))

# 图像可视化
cv.imshow('mask', dst)
cv.waitKey(0)
cv.destroyAllWindows()

二值化图像

# 产生一个图像(从白色到黑色的递增的形式)
img = np.arange(255, -1, -1).reshape((1, -1))
for i in range(255):
    img = np.append(img, np.arange(255, -1, -1).reshape((1, -1)), axis=0)
img = img.astype(np.uint8)

# 进行普通二值化操作(第一个参数是返回的阈值,第二个参数返回的是二值化之后的图像)
# 普通二值化操作, 将小于等于阈值thresh的设置为0,大于该值的设置为maxval
ret, thresh1 = cv.threshold(src=img, thresh=127, maxval=255, type=cv.THRESH_BINARY)
# 反转的二值化操作, 将小于等于阈值thresh的设置为maxval,大于该值的设置为0
ret, thresh2 = cv.threshold(src=img, thresh=127, maxval=255, type=cv.THRESH_BINARY_INV)
# 截断二值化操作,将小于等于阈值thresh的设置为原始值,大于该值的设置为maxval
ret,thresh3 = cv.threshold(img,127,255,cv.THRESH_TRUNC)
# 0二值化操作,将小于等于阈值的设置为0,大于该值的设置为原始值
ret,thresh4 = cv.threshold(img,127,255,cv.THRESH_TOZERO)
# 反转0二值化操作,将小于等于阈值的设置为原始值,大于阈值的设置为0
ret,thresh5 = cv.threshold(img,127,255,cv.THRESH_TOZERO_INV)

titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):
    plt.subplot(2,3,i+1)
    plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()


import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
# 进行自适应二值化操作
# 因为二值化操作的时候需要给定一个阈值,但是实际情况下阈值不是特别好给定的。
# 所以可以基于本身的图像数据,根据当前区域的像素值获取适合的阈值对当前区域进行二值化操作
img = cv.imread('xiaoren.png',0)

# 普通二值化操作
ret,th1 = cv.threshold(img, 127, 255, cv.THRESH_BINARY)
# 使用均值的方式产生当前像素点对应的阈值,
# 使用(x,y)像素点邻近的blockSize*blockSize区域的均值寄减去C的值
th2 = cv.adaptiveThreshold(img, maxValue=255, adaptiveMethod=cv.ADAPTIVE_THRESH_MEAN_C,
                           thresholdType=cv.THRESH_BINARY, blockSize=11, C=2)
# 使用高斯分布的方式产生当前像素点对应的阈值
# 使用(x,y)像素点邻近的blockSize*blockSize区域的加权均值寄减去C的值,
# 其中权重为和当前数据有关的高斯随机数
th3 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,
                           cv.THRESH_BINARY, 11, 2)

titles = ['Original Image', 'Global Thresholding (v = 127)',
            'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]
for i in range(4):
    plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()
![image.png](https://upload-images.jianshu.io/upload_images/5649247-41a66a4865c4079c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

图像平滑/图像模糊filter操作

功能:降低噪音数据对应图像判断的影响

均值滤波

选择窗口中的所有值的均值作为输出值

# OpenCV自带的均值filter
# 加载图像
img = cv.imread('xiaoren.png')


# 做一个卷积操作
dst = cv.blur(img, ksize=(11,11))

# 可视化
plt.subplot(121)
plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
plt.title('Original')

plt.subplot(122)
plt.imshow(cv.cvtColor(dst, cv.COLOR_BGR2RGB))
plt.title('Averaging')
plt.show()

高斯滤波

窗口滤波过程中对应的卷积参数是通过高斯函数计算出来的,特点是中间区域的权重系数大,而周边区域的权重系数小。 作用:去除高斯噪声数据以及图像模糊化操作

# 查看5*5的高斯卷积kernel
# 窗口大小5*5,标准差为1
a = cv.getGaussianKernel(5,1, ktype=cv.CV_64F)
print(a)
kernel = np.dot(a, a.T)
print(kernel)


# OpenCV自带的高斯filter过滤器
# 加载图像
img = cv.imread('koala.png')


# 做一个卷积操作
# ksize:给定窗口大小
# sigmaX: 给定横向的kernel中,参数的标准差
# sigmaY: 给定纵向的kernel中,参数的标准差
dst = cv.GaussianBlur(img, ksize=(3,3), sigmaX=2.0, sigmaY=2.0)

# 可视化
plt.subplot(121)
plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
plt.title('Original')

plt.subplot(122)
plt.imshow(cv.cvtColor(dst, cv.COLOR_BGR2RGB))
plt.title('GaussianBlur1')
plt.show()

![image.png](https://upload-images.jianshu.io/upload_images/5649247-3cf2fef08e3fdd77.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

中值滤波

选择窗口区域中的中值作为输出值

# 中值过滤
# 加载图像
img = cv.imread('xiaoren.png')
noisy_img = np.random.normal(10, 10, (img.shape[0], img.shape[1], img.shape[2]))
noisy_img = np.clip(noisy_img, 0, 255).astype(np.uint8)
img = img + noisy_img

# 转换为灰度图像
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

# 做一个中值过滤
dst = cv.medianBlur(img, ksize=5)

# 可视化
plt.subplot(121)
plt.imshow(img, 'gray')
plt.title('Original')

plt.subplot(122)
plt.imshow(dst, 'gray')
plt.title('medianBlur')
plt.show()

双边滤波

提取图像的纹理、条纹信息

# 双边滤波: 中间的纹理删除,保留边缘信息
# 加载图像
img = cv.imread('xiaoren.png')

# 做一个双边滤波
dst = cv.bilateralFilter(img, d=9, sigmaColor=75, sigmaSpace=75)

# 可视化
plt.subplot(121)
plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
plt.title('Original')

plt.subplot(122)
plt.imshow(cv.cvtColor(dst, cv.COLOR_BGR2RGB))
plt.title('bilateralFilter')
plt.show()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容