目录
前言
这里做一个OpenCV学习笔记的合集。毕竟自己是搞视觉的,我觉得这些还是得懂得。不然,很麻烦。
正文
在Qt5.12上安装opencv
看了巨多的帖子,都是写着要啥cmake啦!要替换啥文件啦,要怎么怎么,都是放狗屁喔!人家opencv的build里面是直接就可以用的。根本不用cmake的。
步骤如下:
- 放置环境变量:
将D:\Study_Software\OpenCV\opencv\build\x64\vc15\bin
还有这个:C:\Qt\Qt5.12.3\5.12.3\msvc2015_64\bin
都放入系统环境变量Path之中。 - 在pro文件中加入这个东西:
INCLUDEPATH += D:/Study_Software/OpenCV/opencv/build/include
Debug:{
LIBS += -lD:/Study_Software/OpenCV/opencv/build/x64/vc14/lib/opencv_world440d
}
Release:{
LIBS += -lD:/Study_Software/OpenCV/opencv/build/x64/vc14/lib/opencv_world440
}
- 先对程序进行qmake一下。
- 文件头加入:
#include <opencv2/opencv.hpp>
- 然后就编写程序就可以使用了:
#include "MainWindow.h"
#include "ui_MainWindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
cv::Mat src = cv::imread("C:/Users/19242/Pictures/01.jpg");
cv::imshow("01.jpg",src);
}
MainWindow::~MainWindow()
{
delete ui;
}
章节
一、图像入门
- 加载图像、保存图像:
code
import numpy as np
import cv2 as cv
img = cv.imread("../../images/lena.jpg")
cv.imshow("img",img)
k = cv.waitKey(0)& 0xFF
if k==27:
cv.destroyAllWindows()
elif k==ord('s'):
cv.imwrite("img2",img)
cv.destroyAllWindows()
cv.getTrackbarPos()
- 第一个参数是轨迹栏名称
- 第二个是它附加到的窗口名称
- 第三个是默认值
- 第四个参数是最大值。
效果
- 使用pyplot显示退选哪个
code
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread("../../images/lena.jpg",0)
plt.imshow(img,cmap='jet')
plt.xticks([]),plt.yticks([])
plt.show()
OpenCV加载的彩色图像处于BGR模式。但是Matplotlib以RGB模式显示。因此,如果使用OpenCV读取彩色图像,则Matplotlib中将无法正确显示彩色图像。
- 读取视频,显示视频
由于我电脑摄像头坏掉了,就无法演示了
code
import numpy as np
import cv2 as cv
cap = cv.VideoCapture(0)
if not cap.isOpened():
print("Can not open Camera")
exit()
while True:
#逐帧捕获
ret,frame = cap.read()
# 若正确读帧,ret为true
if not ret:
print("can not receive frame")
break
二、 OpenCV中的图像绘制功能
首先,先介绍常见的一些参数:
- img:需要绘制的图像
- color:颜色 BGR
- 厚度:闭合图像填-1.默认为1
- lineType:线的类型,是否为8连接线,抗锯齿线
- 绘制图像
code
import numpy as np
import cv2 as cv
img = np.zeros((512,512,3),np.uint8)
cv.line(img,(0,0),(511,511),(255,0,0),5)
cv.rectangle(img,(384,0),(510,128),(0,255,0),3)
cv.circle(img,(447,63), 63, (0,0,255), -1)
cv.ellipse(img,(256,256),(100,50),0,0,180,255,-1)
pts = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32)
pts = pts.reshape((-1,1,2))
cv.polylines(img,[pts],True,(0,255,255))
font = cv.FONT_HERSHEY_SIMPLEX
cv.putText(img,'OpenCV',(10,500), font, 4,(255,255,255),2,cv.LINE_AA)
cv.imshow("img",img)
cv.waitKey(0)
cv.destroyAllWindows()
三、鼠标作为画笔
- 鼠标事件画矩形
code
import numpy as np
import cv2 as cv
def draw_circle(event,x,y,flags,param):
if event==cv.EVENT_LBUTTONDBLCLK:
cv.circle(img,(x,y),100,(255,0,0),-1)#闭合的图形的话,要求,最后一个元素是-1
img = np.zeros((512,512,3),np.uint8)
cv.namedWindow('image')
cv.setMouseCallback('image',draw_circle)
while(1):
cv.imshow('image',img)
if cv.waitKey(20)&0xFF==27:
break;
cv.destroyAllWindows()
双击出现图像。
- 鼠标事件画矩形,按下m键码后,为绘制线
code
import numpy as np
import cv2 as cv
drawing = False#如果按下鼠标,则为真
mode = True#如果为真,绘制矩形
ix,iy = -1,-1
def draw_circle(event,x,y,flags,param):
global drawing,mode,ix,iy#若不加global的话,如果drawing在这被修改了,python会认为这个是一个局部比那里
if event==cv.EVENT_LBUTTONDOWN:# 若鼠标按下,表示当前正在绘画
drawing = True
ix,iy = x,y
elif event ==cv.EVENT_MOUSEMOVE and flags==cv.EVENT_FLAG_LBUTTON:
if drawing ==True:
if mode ==True:
cv.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
else:
cv.circle(img,(x,y),5,(0,0,255),-1)
elif event==cv.EVENT_LBUTTONUP:
drawing = False
img = np.zeros((512,512,3),np.uint8)
cv.namedWindow('image')
cv.setMouseCallback('image',draw_circle)
while(1):
cv.imshow('image',img)
k = cv.waitKey(1)
if k == ord('m'):
mode = not mode
elif k == ord('q'):
break
cv.destroyAllWindows()
鼠标事件有哪些?
#define CV_EVENT_MOUSEMOVE 0 //滑动
#define CV_EVENT_LBUTTONDOWN 1 //左键点击
#define CV_EVENT_RBUTTONDOWN 2 //右键点击
#define CV_EVENT_MBUTTONDOWN 3 //中键点击
#define CV_EVENT_LBUTTONUP 4 //左键放开
#define CV_EVENT_RBUTTONUP 5 //右键放开
#define CV_EVENT_MBUTTONUP 6 //中键放开
#define CV_EVENT_LBUTTONDBLCLK 7 //左键双击
#define CV_EVENT_RBUTTONDBLCLK 8 //右键双击
#define CV_EVENT_MBUTTONDBLCLK 9 //中键双击
- 绘制不填充的矩形
code
# 绘制一个不填充的矩形
# 绘制未填充的矩形
import numpy as np
import cv2 as cv
drawing = False # 如果按下鼠标,则为真
mode = True # 如果为真,绘制矩形。按m键可以切换到曲线
ix, iy = -1, -1
# 鼠标回调函数
def draw_circle(event, x, y, flags, param):
global ix, iy, drawing, mode
if event == cv.EVENT_LBUTTONDOWN:#按下表示开始绘画
drawing = True
ix, iy = x, y
# elif event == cv.EVENT_MOUSEMOVE:
# if drawing == True:
# if mode == True:
# pass
# else:
# cv.circle(img,(x.y),5,(0,0,255),1)
elif event == cv.EVENT_LBUTTONUP:#左键抬起,表示要出效果了
drawing = False
if mode == True:
cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), 1)
else:
cv.circle(img, (x, y), abs(x - ix), (0, 0, 255), 1)
# 创建一个黑色的图像,一个窗口,并绑定到窗口的功能
img = np.zeros((512, 512, 3), np.uint8)
cv.namedWindow('image')
cv.setMouseCallback('image', draw_circle)
while (1):
cv.imshow('image', img)
if cv.waitKey(20) & 0xFF == 27:
break
elif cv.waitKey(20) & 0xFF == ord('m'):
mode = not mode
cv.destroyAllWindows()
四、轨迹栏作为调色板
- 弄一个轨迹栏,调整颜色
code
import numpy as np
import cv2 as cv
def nothing(x):
pass
img = np.zeros((512, 512, 3), np.uint8)
cv.namedWindow('image')
# 创建颜色变化的轨迹栏
cv.createTrackbar("R",'image',0,255,nothing)# 创建三个轨迹栏。控制其值
cv.createTrackbar("G",'image',0,255,nothing)
cv.createTrackbar("B",'image',0,255,nothing)
# 为on/off功能创建开关
switch = '0:OFF/n1:ON'
cv.createTrackbar(switch,'image',0,1,nothing)
while(1):
cv.imshow("image",img)
k = cv.waitKey(1)&0xFF
if k==27:
break
r = cv.getTrackbarPos('R','image')
g = cv.getTrackbarPos('G', 'image')
b = cv.getTrackbarPos('B', 'image')
s = cv.getTrackbarPos(switch, 'image')
if s ==0:
img[:] = 0
else:
img[:] = [b,g,r]# 注意图片的顺序是BGR
cv.destroyAllWindows()
- 使用轨迹栏创建颜色和画笔半径可调的Paint应用程序。
code
#使用轨迹栏创建颜色和画笔半径可调的Paint应用程序。有关绘制的信息,请参阅有关鼠标处 理的先前教程。
import numpy as np
import cv2 as cv
# 鼠标回调函数
def draw_circle(event, x, y,thick,param):
global ix, iy, drawing, mode,color,thicness
if event == cv.EVENT_LBUTTONDOWN:#鼠标按下,表示开始绘画
drawing = True
ix, iy = x, y
elif event == cv.EVENT_MOUSEMOVE:#鼠标移动,画小圆圈,笔的大小有thickness控制
if drawing == True:
cv.circle(img, (x, y), thicness, color, -1,cv.LINE_AA )
elif event == cv.EVENT_LBUTTONUP:#当绘画结束,则置标志位为False
drawing = False
def nothing(x):
pass
# 创建一个的图像,一个窗口
img = np.full((300, 512, 3), 255, np.uint8)
cv.namedWindow('image')
cv.imshow('image', img)
# 创建颜色变化的轨迹栏
cv.createTrackbar('R', 'image', 0, 255, nothing)
cv.createTrackbar('G', 'image', 0, 255, nothing)
cv.createTrackbar('B', 'image', 0, 255, nothing)
cv.createTrackbar('Thickness', 'image', 1, 10, nothing)
color=[0,0,0]
drawing = False
thicness=5
cv.setMouseCallback('image', draw_circle)# 鼠标回调函数
#cv.SetMouseCallback(windowName, onMouse, param=None) → None
while (1):
cv.imshow('image', img)
k = cv.waitKey(1) & 0xFF
if k == 27:
break
# 得到四条轨迹的当前位置
r = cv.getTrackbarPos('R', 'image')
g = cv.getTrackbarPos('G', 'image')
b = cv.getTrackbarPos('B', 'image')
thicness=cv.getTrackbarPos('Thickness', 'image')
color=[b,g,r]
cv.destroyAllWindows()
五、图像的基础操作
- 像素访问与修改:
img.item(10,10,2)
修改RED值:img.itemset((10,10,2),2)
- 拆分和合并图像通道
b,g,r = cv.split(img)
img = cv.merge(b,g,r)
cv.copyMakeBorder
code
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
BLUE = [255,0,0]
img1 = cv.imread('../../images/opencv_logo.png')
replicate = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REPLICATE)
reflect = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT)
reflect101 = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT_101)
wrap = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_WRAP)
constant= cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_CONSTANT,value=BLUE)
plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL')
plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE')
plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101')
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
plt.show()
六、图像的算术运算
- 图像的融合:使用cv.addWeighted和cv.resize()
code
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img1 = cv.imread('../../images/ml.png')
img2 = cv.imread('../../images/opencv-logo.png')
img3 = cv.resize(img2,(308,380))
dst = cv.addWeighted(img1,0.7,img3,0.3,0)
cv.imshow('dst',dst)
cv.waitKey(0)
cv.destroyAllWindows()
- 掩膜的概念:
数字图像处理中的掩膜的概念是借鉴于PCB制版的过程,在半导体制造中,许多芯片工艺步骤采用光刻技术,用于这些步骤的图形“底片”称为掩膜(也称作“掩模”),其作用是:在硅片上选定的区域中对一个不透明的图形模板遮盖,继而下面的腐蚀或扩散将只影响选定的区域以外的区域。
图像掩模主要用于:
①提取感兴趣区,用预先制作的感兴趣区掩模与待处理图像相乘,得到感兴趣区图像,感兴趣区内图像值保持不变,而区外图像值都为0。
②屏蔽作用,用掩模对图像上某些区域作屏蔽,使其不参加处理或不参加处理参数的计算,或仅对屏蔽区作处理或统计。
③结构特征提取,用相似性变量或图像匹配方法检测和提取图像中与掩模相似的结构特征。
④特殊形状图像的制作。
七、性能衡量和提升技术
- 方法
code
e1 = cv.getTickCount()
# 你的执行代码
e2 = cv.getTickCount()
time = (e2 - e1)/ cv.getTickFrequency()
- 检查是否启用优化:cv.useOptimized()
- 关闭优化:cv.setUseOptimized(False)
八、改变颜色空间
code
import cv2 as cv
import numpy as np
cap = cv.VideoCapture(0)
## 因为笔记本的摄像头是有问题的,所以,测不了这个程序
while(1):
# 读取帧
_, frame = cap.read()
# 转换颜色空间 BGR 到 HSV
hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
# 定义HSV中蓝色的范围
lower_blue = np.array([110,50,50])
upper_blue = np.array([130,255,255])
# 设置HSV的阈值使得只取蓝色
mask = cv.inRange(hsv, lower_blue, upper_blue)
# 将掩膜和图像逐像素相加
res = cv.bitwise_and(frame,frame, mask= mask)
cv.imshow('frame',frame)
cv.imshow('mask',mask)
cv.imshow('res',res)
k = cv.waitKey(5) & 0xFF
if k == 27:
break
cv.destroyAllWindows()
九、图像的几何变换
- 图像的缩放
code
import cv2 as cv
import numpy as np
## 缩放
img = cv.imread("../../images/lena.jpg")
res = cv.resize(img,None,fx = 0.5,fy = 0.5,interpolation=cv.INTER_CUBIC)
cv.imshow("image",res)
cv.waitKey(0)
cv.destroyAllWindows()
- 图像的平移
该功能需要用到仿射变换:
仿射变换是指在向量空间中进行一次线性变换(乘以一个矩阵)并加上一个平移(加上一个向量),变换为另一个向量空间的过程。
仿射变换可以通过一系列的原子变换的复合来实现包括:平移(Translation)、缩放(Scale)、翻转(Flip)、旋转(Rotation)和错切(Shear).
code
import cv2 as cv
import numpy as np
## 平移
img = cv.imread("../../images/lena.jpg")
rows,cols = img.shape[:2]
M = np.float32([[1,0,100],[0,1,50]])
dst = cv.warpAffine(img,M,(cols,rows))#2X3的变换矩阵
cv.imshow("image",dst)
cv.waitKey(0)
cv.destroyAllWindows()
- 图像的旋转
code
import cv2 as cv
import numpy as np
img = cv.imread("../../images/lena.jpg");
rows,cols = img.shape[:2]
M = cv.getRotationMatrix2D(((cols-1)/2.0,(rows-1)/2.0),90,1)
dst = cv.warpAffine(img,M,(cols,rows))
cv.imshow('image',dst)
cv.waitKey(0)
cv.destroyAllWindows()