jetson nano opencv 打开 CSI摄像头_OpenCV基础操作-读取、几何变换、阈值

15ae8ffa4c416106501ba8fe61e2a180.png

基本元素图片

OpenCV中彩色图是以B-G-R通道顺序存储的,灰度图只有一个通道,图像坐标的起始点是在左上角,所以行对应的是y,列对应的是x。

cc0aa213df9a13eede4382dc0d083ed9.png
import cv2

img = cv2.imread('lena.jpg',0)

# 先定义窗口,后显示图片
cv2.namedWindow('lena2', cv2.WINDOW_NORMAL)

cv2.imshow('lena', img)
k = cv2.waitKey(0)
# ord()用来获取某个字符的编码
if k == ord('s'):
    cv2.imwrite('lena_save.bmp', img)

1. cv2.imread(): - cv2.IMREAD_COLOR:彩色图,默认值(1) - cv2.IMREAD_GRAYSCALE:灰度图(0) - cv2.IMREAD_UNCHANGED:包含透明通道的彩色图(-1)

2. cv2.namedWindow()创建一个窗口 - 参数1依旧是窗口的名字 - 参数2默认是cv2.WINDOW_AUTOSIZE,表示窗口大小自适应图片,也可以设置为cv2.WINDOW_NORMAL,表示窗口大小可调 - 图片比较大的时候,可以考虑用后者。

摄像头

❗ ️详细内容参考:http://ex2tron.wang/opencv-python-open-camera/

要使用摄像头,需要使用cv2.VideoCapture(0)创建VideoCapture对象,参数0指的是摄像头的编号,如果你电脑上有两个摄像头的话,访问第2个摄像头就可以传入1,依此类推。

# 打开摄像头并灰度化显示
import cv2
capture = cv2.VideoCapture(0)
while(True):
    # 获取一帧
    ret, frame = capture.read()
    # 将这帧转换为灰度图
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    cv2.imshow('frame', gray)
    if cv2.waitKey(1) == ord('q'):
        break

按位运算

想把 OpenCV 的标志放到另一幅图像上。如果我使用加法颜色会改变,如果使用混合虽会得到透明效果,但是不想要透明。如果他是矩形我可以使用ROI。但是他不是矩形。但是我们可以通过按位运算实现。

import cv2
import numpy as np
# load图像
img1 = cv2.imread('lena.jpg')
img2 = cv2.imread('opencv-logo-white.png')

# 把logo放到图像左上角
rows, cols = img2.shape[:2]
roi = img1[:rows,:cols]

# 创建掩码
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY)
# 逆掩码(背景白,logo黑)
mask_inv = cv2.bitwise_not(mask)
img1_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)
#只提取出logo的像素
img2_fg = cv2.bitwise_and(img2, img2, mask=mask)
# 把前景和背景合并
dst = cv2.add(img1_bg, img2_fg)
# roi放入原图
img1[:rows,:cols] = dst
#显示
dd = np.hstack((img1_bg,dst))
cc = np.hstack((mask,mask_inv))
cv2.namedWindow('res',cv2.WINDOW_NORMAL)
cv2.namedWindow('rses',cv2.WINDOW_NORMAL)
cv2.imshow('res',cc)
cv2.imshow('rses',dd)
cv2.waitKey(0)
cv2.destroyAllWindows()

f71eb4d1f260724db7d1041a29c66b56.png

3016dbc2b8c31a7d04a60da4a9360e3b.png

图像几何变换

  • 实现旋转、平移和缩放图片
  • OpenCV函数:cv2.resize(), cv2.flip(), cv2.warpAffine()

缩放:

OpenCV 提供的函数cv2.resize()可以实现,图像的尺寸可以自己手动设置虽你也可以指定缩放因子。我们可以选择择使用不同的插值方法。在缩放时我们推荐使用cv2.INTER_AREA虽在扩展时我们推荐使用v2.INTER_CUBIC较慢)和v2.INTER_LINEAR是cv2.INTER_LINEAR。

翻转:

镜像翻转图片,可以用cv2.flip()函数:

dst = cv2.flip(img, 1)

其中,参数2 = 0:垂直翻转(沿x轴),参数2 > 0: 水平翻转(沿y轴),参数2 < 0: 水平垂直翻转。

平移:

如果需要沿 $(x,y)$方向移动,移动的距离是$(t_x,t_y)$,需要构建下面的移动矩阵:

你可以使用 Numpy 数组构建这个矩阵,数据类型是 np.float32,然后把它传给函数 cv2.warpAffine()。

# 平移图片
import numpy as np
rows, cols = img.shape[:2]
# 定义平移矩阵,需要是numpy的float32类型
# x轴平移100,y轴平移50
M = np.float32([[1, 0, 100], [0, 1, 50]])
# 用仿射变换实现平移
dst = cv2.warpAffine(img, M, (rows, cols))  #需要图像、变换矩阵、变换后的大小
cv2.imshow('shift', dst)
cv2.waitKey(0)

4e904c8f89f85468fc04b85a7f804efe.png
平移

旋转:

4cff31a99c4ea8dab5aeeac815f72973.png

旋转同平移一样,也是用仿射变换实现的,因此也需要定义一个变换矩阵。OpenCV直接提供了 cv2.getRotationMatrix2D() 函数来生成这个矩阵,该函数有三个参数:

  • 参数1:图片的旋转中心
  • 参数2:旋转角度(正:逆时针,负:顺时针)
  • 参数3:缩放比例,0.5表示缩小一半
# 45°旋转图片并缩小一半
M = cv2.getRotationMatrix2D((cols / 2, rows / 2), 45, 0.5)
dst = cv2.warpAffine(img, M, (cols, rows))
cv2.imshow('rotation', dst)
cv2.waitKey(0)

3fca92ee1c81cc264b21c157ce031f0a.png

透视变换:

对于视觉变换虽我们需要一个3x3变换矩阵。在变换前后直线还是是直线。要构建这个变换矩阵,需要在图像上找4个点,以及他们在输出图像上对应的位置。这四个点中的任意三个点不能共线。这个变换矩阵可以有函数cv2.getPerspectiveTransform()构建。然后把这个矩俤传给函数cv2.warpPerspective

img = cv2.imread('sudoku.jpg')
rows,cols,ch = img.shape
# 原图的四个点
pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
# 输出图像的四个顶点
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
# 变换
M = cv2.getPerspectiveTransform(pts1,pts2)
# 仿射
dst = cv2.warpPerspective(img,M,(300,300))
# 显示
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()

4e1a16b9a8691ec65d8e0b4bd089f960.png
透视变换

图像阈值

  • ⛳️ 使用固定阈值、自适应阈值和Otsu阈值法”二值化”图像
  • ⛳️ OpenCV函数:cv2.threshold(), cv2.adaptiveThreshold()

简单阈值

当像素值高于阈值时,我们给这个像素赋予一个新值(可能是白色),否则我们给它赋予另外一种颜色(可能是黑色)。这个函数就是 cv2.threshhold()

737e2cc411438ac6f7df4cebae1e4f35.png
阈值

cv2.threshold() 用来实现阈值分割,ret是return value缩写,代表当前的阈值,暂时不用理会。函数有4个参数:

  • 参数1:要处理的原图,一般是灰度图
  • 参数2:设定的阈值
  • 参数3:最大阈值,一般为255
  • 参数4:阈值的方式,主要有5种
    • cv.THRESH_BINARY
    • cv.THRESH_BINARY_INV
    • cv.THRESH_TRUNC
    • cv.THRESH_TOZERO
    • cv.THRESH_TOZERO_INV
import matplotlib.pyplot as plt
# 应用5种不同的阈值方法
ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
ret, th2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
ret, th3 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
ret, th4 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
ret, th5 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)
titles = ['Original', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, th1, th2, th3, th4, th5]
# 使用Matplotlib显示
for i in range(6):
    plt.subplot(2, 3, i + 1)
    plt.imshow(images[i], 'gray')
    plt.title(titles[i], fontsize=8)
    plt.xticks([]), plt.yticks([])  # 隐藏坐标轴
plt.show()

511f0a9d0a54e35cd3cf8feb5b7c0f5b.png
不同对比

附表:

a2ec731a7675fd27a7ff2476bc896ce7.png

自适应阈值

固定阈值是在整幅图片上应用一个阈值进行分割,它并不适用于明暗分布不均的图片。 cv2.adaptiveThreshold()自适应阈值会每次取图片的一小部分计算阈值,这样图片不同区域的阈值就不尽相同,从而使我们能在亮度不同的情况下得到更好的结果。

img = cv2.imread('sudoku.jpg', 0)

#固定阈值
ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)

#自适应阈值
th2 = cv2.adaptiveThreshold(
    img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 4)

th3 = cv2.adaptiveThreshold(
    img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 17, 6)

titles = ['Original', 'Global(v = 127)', 'Adaptive Mean', 'Adaptive Gaussian']
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], fontsize=8)
    plt.xticks([]), plt.yticks([])
plt.show()

50a7d7e701cf8b2d0a7717769101d2b4.png
自适应阈值
  • 参数1:要处理的原图
  • 参数2:最大阈值,一般为255
  • 参数3:小区域阈值的计算方式☘️
    • ADAPTIVE_THRESH_MEAN_C:小区域内取均值
    • ADAPTIVE_THRESH_GAUSSIAN_C:小区域内加权求和,权重是个高斯核
  • 参数4:阈值方式(跟前面讲的那5种相同)
  • 参数5:小区域的面积,如11就是11*11的小块
  • 参数6:最终阈值等于小区域计算出的阈值再减去此值

Otsu阈值

大部分的图像处理任务都需要进行二值化处理,阈值的选取很重要,Otsu阈值法可以自动计算阈值,而且该方法非常适合双峰图片。

这里用到的函数是 cv2.threshold(),但是需要多传入一个参数(flag):cv2.THRESH_OTSU,这时把阈值设置为0。然后算法会找到最优阈值,这个最优阈值就是返回值 retVal。如果不使用 Otsu 二值化,返回的retVal 值与设定的阈值相等。

❓问:什么是双峰图片?

❗答:双峰图片就是指图片的灰度直方图上有两个峰值,直方图就是每个值(0~255)的像素点个数统计。

a75952bbac625b294292945507052941.png

Otsu算法假设这副图片由前景色和背景色组成,通过统计学方法(最大类间方差)选取一个阈值,将前景和背景尽可能分开。

☘️下面这段代码对比了使用固定阈值和Otsu阈值后的不同结果:

☘️另外,对含噪点的图像,先进行滤波操作效果会更好。

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('noisy.jpg', 0)

# 固定阈值
ret1, th1 = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)

# Otsu阈值
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# 先进行高斯滤波,在使用Otsu阈值
blur = cv2.GaussianBlur(img, (5,5), 0)
ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# 可视化
images = [img, 0, th1, img, 0, th2, blur, 0, th3]
titles = ['Original', 'Histogram', 'Global(v=100)',
          'Original', 'Histogram', "Otsu's",
          'Gaussian filtered Image', 'Histogram', "Otsu's"]
for i in range(3):
    # 绘制原图
    plt.subplot(3, 3, i * 3 + 1)
    plt.imshow(images[i * 3], 'gray')
    plt.title(titles[i * 3], fontsize=8)
    plt.xticks([]), plt.yticks([])
    # 绘制直方图plt.hist,ravel函数将数组降成一维
    plt.subplot(3, 3, i * 3 + 2)
    plt.hist(images[i * 3].ravel(), 256)
    plt.title(titles[i * 3 + 1], fontsize=8)
    plt.xticks([]), plt.yticks([])
    # 绘制阈值图
    plt.subplot(3, 3, i * 3 + 3)
    plt.imshow(images[i * 3 + 2], 'gray')
    plt.title(titles[i * 3 + 2], fontsize=8)
    plt.xticks([]), plt.yticks([])
plt.show()

bfbdbf6c1d79f9f078553cd690624d64.png
对比

PS: 绘制直方图时,使用了numpy中的ravel()函数,它会将原矩阵压缩成一维数组,便于画直方图。

Otsu 算法详解: Otsu阈值法将整幅图分为前景(目标)和背景,以下是一些符号规定:

  • T:分割阈值
  • N0:前景像素点数
  • N1:背景像素点数
  • ω0:前景的像素点数占整幅图像的比例
  • ω1:背景的像素点数占整幅图像的比例
  • μ0:前景的平均像素值
  • μ1:背景的平均像素值
  • μ:整幅图的平均像素值
  • rows×cols:图像的行数和列数 结合下图会更容易理解一些,有一副大小为4×4的图片,假设阈值T为1,那么:

37653826abddbc9e59e848e30b14f211.png

其实很好理解,

就是总的像素点个数,也就是行数乘列数:

是前/背景所占的比例,也就是:

整幅图的平均像素值就是:

此时,我们定义一个前景

与背景
的方差

将前述的1/2/3公式整合在一起,便是:

就是前景与背景两类之间的方差,这个值越大,说明前景和背景的差别也就越大,效果越好。Otsu算法便是遍历阈值T,使得g最大,所以又称为最大类间方差法 。基本上双峰图片的阈值T在两峰之间的谷底。

------------------------------------------可爱の分割线------------------------------------------

更多Opencv教程可以 Follow github的opencv教程,中文&English 欢迎Star❤️❤️❤️

https://github.com/JimmyHHua/opencv_tutorials​github.com

参考

❗ ❗ ❗ Thanks: ❗ ❗ ❗

- ex2tron

- OpenCv

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值