最近在学习opencv的一些知识,现在记录下:
1. opencv 安装
新建install-opencv-and-contrib.sh 脚本,脚本 内容如下:
# VERSION TO BE INSTALLED
OPENCV_VERSION='4.5.1'
OPENCV_CONTRIB=1
OPENCV_DIR_NAME=opencv-${OPENCV_VERSION}
CONTRIB_DIR_NAME=opencv_contrib-${OPENCV_VERSION}
CURRENT_DIR=`pwd`
CONTRIB_MODULES_DIR="${CURRENT_DIR}/${CONTRIB_DIR_NAME}/modules"
FLAGS=
FLAGS="${FLAGS} -DBUILD_JAVA=OFF"
FLAGS="${FLAGS} -DBUILD_opencv_java=OFF"
FLAGS="${FLAGS} -DCMAKE_CXX_COMPILER=g++"
FLAGS="${FLAGS} -DCMAKE_C_COMPILER=gcc"
FLAGS="${FLAGS} -DBUILD_TESTS=OFF"
FLAGS=“${FLAGS} -DOPENCV_ENABLE_NONFREE=ON”
# 1. KEEP UBUNTU OR DEBIAN UP TO DATE
sudo apt-get -y update
# sudo apt-get -y upgrade # Uncomment this line to install the newest versions of all packages currently installed
# sudo apt-get -y dist-upgrade # Uncomment this line to, in addition to 'upgrade', handles changing dependencies with new versions of packages
# sudo apt-get -y autoremove # Uncomment this line to remove packages that are now no longer needed
# 2. INSTALL THE DEPENDENCIES
# Build tools:
sudo apt-get install -y build-essential cmake
# GTK
sudo apt-get install -y libgtk2.0-dev
# GUI (if you want to use GTK instead of Qt, replace 'qt5-default' with 'libgtkglext1-dev' and remove '-DWITH_QT=ON' option in CMake):
sudo apt-get install -y qt5-default libvtk6-dev
# Media I/O:
sudo apt-get install -y zlib1g-dev libjpeg-dev libwebp-dev libpng-dev libtiff5-dev libjasper-dev libopenexr-dev libgdal-dev
# Video I/O:
sudo apt-get install -y libdc1394-22-dev libavcodec-dev libavformat-dev libswscale-dev libtheora-dev libvorbis-dev libxvidcore-dev libx264-dev yasm libopencore-amrnb-dev libopencore-amrwb-dev libv4l-dev libxine2-dev
# Parallelism and linear algebra libraries:
sudo apt-get install -y libtbb-dev libeigen3-dev
# Python:
sudo apt-get install -y python-dev python-tk python-numpy python3-dev python3-tk python3-numpy
# Java:
sudo apt-get install -y ant default-jdk
# Documentation:
sudo apt-get install -y doxygen
# 3. INSTALL THE LIBRARY
# install unzip wget
sudo apt-get install -y unzip wget
wget https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip -O ${OPENCV_DIR_NAME}.zip
unzip -o ${OPENCV_DIR_NAME}.zip
rm ${OPENCV_DIR_NAME}.zip
if [ ${OPENCV_CONTRIB} -eq 1 ]; then
wget https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip -O ${CONTRIB_DIR_NAME}.zip
unzip -o ${CONTRIB_DIR_NAME}.zip
rm ${CONTRIB_DIR_NAME}.zip
FLAGS="${FLAGS} -DOPENCV_EXTRA_MODULES_PATH=${CONTRIB_MODULES_DIR}"
fi
# mv opencv-${OPENCV_VERSION} OpenCV
# cd OpenCV
cd ${OPENCV_DIR_NAME}
mkdir -p build
cd build
echo "cmake ${FLAGS} .."
cmake ${FLAGS} ..
make -j4
sudo make install
sudo ldconfig
我安装的opencv=4.5.1 ;其中opencv 和 opencv_contrib 的版本必须保证版本一致,防止引发其它问题
执行脚本:
./install-opencv-and-contrib.sh
2. opencv 函数
(1)边缘检测: cv2.Canny()
edges = cv2.Canny( image, threshold1, threshold2[, apertureSize[, L2gradient]])
edges 为计算得到的边缘图像。
image 为 8 位输入图像,原始图像
threshold1 表示处理过程中的第一个阈值。
threshold2 表示处理过程中的第二个阈值。
低于阈值1的像素点会被认为不是边缘;
高于阈值2的像素点会被认为是边缘;
在阈值1和阈值2之间的像素点,若与第2步得到的边缘像素点相邻,则被认为是边缘,否则被认为不是边缘。
实例应用:
import cv2
img=cv2.imread("1111.png",cv2.IMREAD_GRAYSCALE)
edges_img=cv2.Canny(img,100,200) #阈值范围越小,越大,检测的边缘线越密
cv2.imshow("img",img)
cv2.imshow("edges_img",edges_img)
cv2.waitKey(0)
img:
edges_img:
(2) cv2.cvtColor() 颜色空间转换
imgGray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 彩色图转灰度图
(3) cv2.adaptiveThreshold() 二值化图像
用于图像自适应阈值二值化, 通过规定一个区域大小,比较处理像素点与区域大小里面像素点的平均值。阈值(或者其他特征)的大小关系确定这个像素点是属于黑或者白(如果是二值情况)。
dst = cv2.adaptiveThreshold(gray, maxval, thresh_type, type, Block Size, C)
dst: 输出图
src: 输入图,只能输入单通道图像,通常来说为灰度图
maxval: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
thresh_type: 阈值的计算方法,包含以下2种类型:(cv2.ADAPTIVE_THRESH_MEAN_C: 区域内均值cv2.ADAPTIVE_THRESH_GAUSSIAN_C: 区域内像素点加权和,权重为一个高斯窗口)
type:二值化操作的类型,与固定阈值函数相同,用于控制参数2 maxval,一般选择:cv2.THRESH_BINARY: 黑白二值; cv2.THRESH_BINARY_INV:黑白二值反转
Block Size: 图片中区域的大小,取奇数,当blockSize越大,参与计算阈值的区域也越大,细节轮廓就变得越少,整体轮廓越粗越明显
C :阈值计算方法中的常数项,当C越大,每个像素点的N*N邻域计算出的阈值就越小,中心点大于这个阈值的可能性也就越大,设置成255的概率就越大,整体图像白色像素就越多,反之亦然。
实例应用:
import cv2
img=cv2.imread("1111.png",cv2.IMREAD_GRAYSCALE)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
imgThresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 101, 20)
cv2.imshow("imgThresh",imgThresh)
cv2.waitKey(0)
(4) 霍夫变换检测直线
list_of_lines =cv2.HoughLinesP(image, rho=0.1, theta=np.pi/180, threshold=15, minLineLength=9, maxLineGap=4)
list_of_lines: 输出线段值(起始点坐标,终点坐标)
image: 必须是二值图像,推荐使用canny边缘检测的结果图像;
rho: 线段以像素为单位的距离精度,double类型的,推荐用1.0 theta: 线段以弧度为单位的角度精度,推荐用numpy.pi/180,表示要搜索所有可能的角度; numpy.pi/2, 表示搜索水平方向的直线
threshod: 累加平面的阈值参数,int类型,超过设定阈值才被检测出线段,值越大,基本上意味着检出的线段越长,检出的线段个数越少。识别直线时,要判定有多少个点位于该直线上。在判定直线是否存在时,对直线所穿过的点的数量进行评估,如果直线所穿过的点的数量小于阈值,则认为这些点恰好(偶然)在算法上构成直线,但是在源图像中该直线并不存在;如果大于阈值,则认为直线存在。
lines:这个参数的意义未知,发现不同的lines对结果没影响,但是不要忽略了它的存在
minLineLength:线段以像素为单位的最小长度,根据应用场景设置
maxLineGap:同一方向上两条线段判定为一条线段的最大允许间隔(断裂),超过了设定值,则把两条线段当成一条线段,值越大,允许线段上的断裂越大,越有可能检出潜在的直线段
实例应用
import cv2
img = cv2.imread('test.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150)
lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength=100,maxLineGap=10)
for line in lines:
x1,y1,x2,y2 = line[0]
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
cv2.imshow("edges",edges)
cv2.imshow("img",img)
cv2.waitKey(0)
(5) FLD直线检测算法,有关函数:
需要先下载安装 pip install opencv-contrib-python
fld = cv2.ximgproc.createFastLineDetector() 创建一个FLD对象
dlines = fld.detect(img) 找直线,传入的参数就是要找直线的图像;
fld.drawSegments(img,dlines) 在图上把直线画出来,输入就是要画直线的图像和detect的输出。
实例应用
# coding=utf-8
import cv2
# 读取输入图片
img0 = cv2.imread("test.jpg")
# 将彩色图片转换为灰度图片
img = cv2.cvtColor(img0,cv2.COLOR_BGR2GRAY)
# 创建一个LSD对象
fld = cv2.ximgproc.createFastLineDetector()
# 执行检测结果
dlines = fld.detect(img)
# 绘制检测结果
# drawn_img = fld.drawSegments(img0,dlines)
for dline in dlines:
x0 = int(round(dline[0][0]))
y0 = int(round(dline[0][1]))
x1 = int(round(dline[0][2]))
y1 = int(round(dline[0][3]))
cv2.line(img0, (x0, y0), (x1,y1), (0,255,0), 1, cv2.LINE_AA)
# 显示并保存结果
cv2.imshow("LSD", img0)
cv2.waitKey(0)
cv2.destroyAllWindows()
(6) 画框:
cv2.rectangle(img, pt1, pt2, color, thickness, lineType, shift )
参数表示依次为: (图片,长方形框左上角坐标, 长方形框右下角坐标, 字体颜色,字体粗细)
在图片img上画长方形,坐标原点是图片左上角,向右为x轴正方向,向下为y轴正方向
实例应用
cv2.rectangle(img, (x1,y1), (x2,y2),(0,255,0),-1) #目标识别画框
(7)cv2.line() 画线段
cv2.line(image, start_point, end_point, color, thickness)
image: 图像,要在哪个图上画线就输入哪个图
start_point:它是线的起始坐标。坐标表示为两个值的元组,即(X坐标值,Y坐标值)。
end_point: 它是线的起始坐标。坐标表示为两个值的元组,即(X坐标值,Y坐标值)。
color: 它是要绘制的线条的颜色。对于BGR,我们通过一个元组。例如:(255,0,0)为蓝色。
thickness: 它是线的粗细像素。
(8) cv2.circle()
cv2.circle(img, center, radius, color(B,G,R), thickness, linetype, shift)
cv2.circle(img_show, (x_new, y_new), 1, (255, 0, 0), 2)
image:它是要在其上绘制圆的图像。
center:它是圆的中心坐标。坐标表示为两个值的元组,即(X坐标值,Y坐标值)。
radius:它是圆的半径。
color:它是要绘制的圆的边界线的颜色。对于BGR,我们通过一个元组。例如:(255,0,0)为蓝色。
thickness:它是圆边界线的粗细像素。厚度-1像素将以指定的颜色填充矩形形状。
lineType: 圆边界的类型,可选参数
shift:中心坐标和半径值中的小数位数,可选参数
返回值:它返回一个图像
(9) cv2.putText()
cv2.putText(image, text, org, font, fontScale, color[, thickness[, lineType[, bottomLeftOrigin]]])
cv2.putText(image, "car", (15,40), FONT_HERSHEY_COMPLEX, 1, (255,0,255), 3)
image:要在其上绘制文本的图像。
text:要绘制的文本字符串。
org:它是图像中文本字符串左下角的坐标。坐标表示为两个值的元组,即(X坐标值,Y坐标值)。
font:它表示字体类型。一些字体类型是FONT_HERSHEY_SIMPLEX,FONT_HERSHEY_PLAIN等。
fontScale:字体比例因子乘以font-specific基本大小。
color:它是要绘制的文本字符串的颜色。对于BGR,我们通过一个元组。例如:(255,0,0)为蓝色。
thickness:它是线的粗细像素。
lineType:这是一个可选参数,它给出了要使用的行的类型。
bottomLeftOrigin:这是一个可选参数。如果为true,则图像数据原点位于左下角。否则,它位于左上角。
(10) cv2.waitkey(delay)
cv2.waitKey(0)
waitKey() 控制着imshow的持续时间,在展示imshow后面使用
delay:视频中一帧数据显示(停留)的时间
(11) 轮廓检测
a. cv2.threshold() 阈值函数
ret, thresh = cv2.threshold(src, thresh, maxval, type[, dst])
src是灰度图像
thresh是起始阈值
maxval是最大值
type是定义如何处理数据与阈值的关系,二值化方法,包含几种类型:
cv2.THRESH_BINARY
cv2.THRESH_BINARY_INV
cv2.THRESH_TRUNC
cv2.THRESH_TOZERO
cv2.THRESH_TOZERO_INV
ret: 阈值,如果 type 为 cv2.THRESH_OTSU 或 cv2.THRESH_TRIANGLE,则该值为自动计算出的最优阈值。
thresh: 处理后的图像
b.cv2.findContours() 轮廓检测函数
cv2.findContours(thresh, mode, method[, contours[, hierarchy[, offset ]]])
thresh:参数是寻找轮廓的图像,二值图像或经过Canny算法处理之后的图像
mode:参数表示轮廓的检索模式,有四种(本文介绍的都是新的cv2接口):
cv2.RETR_EXTERNAL:表示只检测外轮廓
cv2.RETR_LIST:检测的轮廓不建立等级关系
cv2.RETR_CCOMP:建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
cv2.RETR_TREE:建立一个等级树结构的轮廓。
method:轮廓的近似办法:
cv2.CHAIN_APPROX_NONE:存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
cv2.CHAIN_APPROX_SIMPLE:压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS:使用teh-Chinl chain 近似算法
实例
image ,contours,hierarchy =
cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
bug:
ValueError: not enough values to unpack (expected 3, got 2)
OpenCV旧版,返回三个参数:im2, contours, hierarchy = cv2.findContour(mask, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
OpenCV 新版调用,返回两个参数:contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
返回值有三个(im2, contours, hierarchy),第一个是图像,第二个是轮廓,第三个是(轮廓的)层析结构。轮廓(contours)是一个Python列表,其中储存这图像中所有轮廓。
c. 轮廓的绘制cv2.drawContours()
cv2.drawContours(image, contours, contourIdx, color[, thickness[, li ...)
image:指明在哪幅图像上绘制轮廓;
contours:轮廓本身,在Python中是一个list。
contourIdx:指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。
thickness:表明轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式。
实例应用
image_draw = cv2.drawContours(img, contours, -1, (0, 0, 255), 2)
img表示输入的需要画的图片,
contours表示轮廓值,
-1表示轮廓的索引,
(0, 0, 255)表示颜色,
2表示线条粗细
## 绘制检索到的所有轮廓中的第四个
cv.drawContours(img, contours, 3, (0,255,0), 3)
轮廓检测实例
import cv2
img = cv2.imread('1024.jpg')
imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#高斯滤波,可以去除噪点
imgray = cv2.GaussianBlur(imgray, (3,3), 1)
ret,thresh = cv2.threshold(imgray,124,255,0)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
#绘制所有的轮廓
imag = cv2.drawContour(img,contours,-1,(0,255,0),3)
#绘制独立轮廓,如第四个轮廓
#imag = cv2.drawContours(img,contours,3,(0,255,0),2)
cv2.imshow('img', imag)
key = cv2.waitKey(1)
if key & 0xFF == 27:
break
其他相关函数:
cv2.contourArea(cnt, True) 计算轮廓的面积
cv2.arcLength(cnt, True) 计算轮廓的周长
x, y, w, h = cv2.boudingrect(cnt) 获得外接矩形
### opencv最小外接矩形
cv2.threshold() —— 阈值处理
cv2.findContours() —— 轮廓检测
cv2.boundingRect() —— 最大外接矩阵
cv2.rectangle() —— 画出矩形
cv2.minAreaRect —— 找到最小外接矩形(矩形具有一定的角度)
cv2.boxPoints —— 外接矩形的坐标位置
cv2.drawContours(image, [box], 0, (0, 0, 255), 3) —— 根据点画出矩形
x,y, w, h 分别表示外接矩形的x轴和y轴的坐标,以及矩形的宽和高
cnt表示输入的轮廓值
希望以上内容可以帮到您, 欢迎反馈~