视觉学习---opencv函数学习

Posted wqm-story027

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了视觉学习---opencv函数学习相关的知识,希望对你有一定的参考价值。

最近在学习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表示输入的轮廓值

希望以上内容可以帮到您, 欢迎反馈~

Opencv视觉处理(C++)语法学习鼠标操作与相应

认识调用鼠标操作的api及其参数设定

首先说一下原理:首先是在opencv产生的窗口中设定一个监听事件,用来监听鼠标的操作,鼠标的操作将会被系统捕获,然后返回到opencv中的鼠标的响应函数中去,这个响应函数在定义之初就被绑定到鼠标操作的事件上去了,这样的一个流程下来就形成了用户鼠标操作,在opencv窗口中引起相应的变化的这么一个过程。

1.调用鼠标操作的api

setMouseCallback("鼠标操作", on_draw, (void*)(&img));

2.鼠标操作结束之后系统监听到的事件所定义的鼠标响应函数

static void on_draw(int event, int x, int y, int flag, void* userdata)

下面是完整的代码演示

static void on_draw(int event, int x, int y, int flag, void* userdata)
{
	//首先实例化传进来的img
	Mat img = *(Mat*)userdata;
	//然后获取鼠标的停留点
	//1.开始点
	if (event == EVENT_LBUTTONDOWN)
	{
		sp.x = x, sp.y = y;
		std::cout << "the start point is (" << sp.x << "," << sp.y << ")"<<endl;
	}
	else if (event == EVENT_LBUTTONUP)//就是放开鼠标的时候,就要开始计算矩形
	{
		ep.x = x, ep.y = y;
		std::cout << "the end point is (" << sp.x << "," << sp.y << ")" << endl;
		int dx = ep.x - sp.x;
		int dy = ep.y - sp.y;
		if (dx > 0 && dy > 0)
		{
			Rect box(sp.x, sp.y, dx, dy);
			rectangle(img, box, Scalar(0, 0, 255), 2, LINE_AA, 0);
			imshow("鼠标操作", img);
			imshow("ROI区域", img(box));
			sp.x = -1, sp.y = -1;
		}
	}
	else if (event == EVENT_MOUSEMOVE)
	{
		if (sp.x > 0 && sp.y >0 )
		{
			ep.x = x;
			ep.y = y;
			int dx = ep.x - sp.x;
			int dy = ep.y - sp.y;
			if (dx > 0 && dy > 0)
			{
				Rect box(sp.x, sp.y, dx, dy);
				temp.copyTo(img);
				rectangle(img, box, Scalar(0,0,255),2,LINE_8,0);
				imshow("鼠标操作", img);
			}
		}
	}
}

void QuickDemo::Mouse_drawing(Mat &img)
{
	//1.创建窗口,用来显示
	namedWindow("鼠标操作", WINDOW_AUTOSIZE);
	temp = img.clone();
	//2.调用SetmouseCallback,绑定opencv窗口
	setMouseCallback("鼠标操作", on_draw, (void*)(&img));
	//api说明:("窗口名称"(string),将要callback绑定的函数,自定义参数userdata )
	//3.显示窗口imshow("窗口名称",传入图像)
	imshow("鼠标操作", img);
}

以上是关于视觉学习---opencv函数学习的主要内容,如果未能解决你的问题,请参考以下文章

Opencv视觉处理(C++)语法学习鼠标操作与相应

计算机视觉OpenCv学习系列:第十部分实时人脸检测

opencv 入门 学习笔记

OpenCV4.0正式发布 | 谷歌发布大型机器学习数据集

OpenCV学习总结- 视觉系统的构成要素

人工智能计算机视觉之OpenCV学习详解一