opencv基础学习(一)


OpenCV基础学习

学习的是4.2.0版本的OpenCV,在这里只进行C++和python部分代码的实践。

学习链接

没有标识(C++)表示该部分内容有C++和python两种语言实现。

安装环境

安装opencv环境(C++)

原本想着用docker中的opencv image,只不过没办法显示图像,只能单纯的运行无输出程序。所以无奈只能本地安装opencv

一开始借鉴知乎链接,后来发现按照官网教程即可把opencv安装好且不需要额外下载内容(教程里一开始的依赖我都下载了)

注意: 在安装4.2.0之前貌似服务器上就已经装了opencv3.2.0的版本,在编译好之后才发现这个事情。后来发现opencv4X版本与opencv3x版本配置路径时有所不同,所以应该也是不影响的

主机系统:ubuntu18.04

1安装依赖

sudo apt-get install build-essential
sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev

2获取源码

这个知乎教程和官网里面都有,我就不贴了

3编译opencv

首先把opencv_contrib和opencv文件夹解压,然后把opencv_contrib复制到opencv文件夹下。
然后再在opencv文件夹下新建build文件夹,然后切换到build文件夹下
运行以下命令:

cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local .. OPENCV_GENERATE_PKGCONFIG=ON

没有效果的话就运行下面这条:
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local .. OPENCV_GENERATE_PKGCONFIG=ON

然后继续在build目录下运行:
make -j7 #数字可以根据自己的电脑性能适度调整

sudo make install

至此opencv安装完毕,下面配置路径

4配置路径

先在/etc/ld.so.conf.d/文件夹下新建一个opencv4.conf,里面写入/usr/local/lib。

cd /etc/ld.so.conf.d/
sudo touch opencv4.conf
sudo sh -c 'echo "/usr/local/lib" > opencv4.conf'
#更新pkg-config
sudo ldconfig

然后运行以下命令检测是否安装成功

pkg-config --modversion opencv4 #其他版本没有尾后数字  

安装成功

运行测试实例然后就成功了

#原路径在build文件夹时
$ cd ../samples/cpp/example_cmake
$ cmake .
$ make
$ ./opencv_example

测试结果

安装opencv环境(Python)

这个比较简单,在anaconda环境下随便创建个虚拟环境,然后运行下面指令就可以了(其实前面安装好之后本地python也就可以调用cv2,只不过为了本地环境的安全,再新创一个虚拟环境进行python版本的安装)

pip install opencv-python

一、简单入门

使用gcc和cMake编译opencv代码(C++)

在对着教程把相关代码配置好后,前面都很顺利,在make时却发生了意外报错。

由于报错信息太多,一开始有点不知道从何下手,所以在折腾了半天之后在网上搜寻能够保存make报错日志的相关命令:

make>make.log2>&1

参数解释:

  • 2: stderr
  • 1: stdout
  • make.log:要生成的日志文件

大致意思就是把make报错的信息传输到生成的make.log文件中。

然后秉承着先解决最先报的错的原则,我们先解决第一个错误:

error: "OpenCV" 4.x+ requires enabled c++11 support

然后根据网上的相关解答,我在CMakeList.txt文件中首行添加了一行代码,修改后的CmakeList.txt文件内容如下所示:
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fPIC -O3 -std=c++11 -fopenmp")
cmake_minimum_required(VERSION 2.8)
project( DisplayImage )
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_executable( DisplayImage DisplayImage.cpp )
target_link_libraries( DisplayImage ${OpenCV_LIBS} )

再次执行cmake,然后执行make,终于编译成功.最后经测试成功显示图像。

源码解读:

#include <stdio.h>
#include <opencv2/opencv.hpp>
using namespace cv;
int main(int argc, char** argv )
{
    if ( argc != 2 ) //??
    {
        printf("usage: DisplayImage.out <Image_Path>\n");
        return -1;
    }
    Mat image;
    image = imread( argv[1], 1 ); //????
    if ( !image.data ) //如果为空?
    {
        printf("No image data \n");
        return -1;
    }
    namedWindow("Display Image", WINDOW_AUTOSIZE );
    imshow("Display Image", image);
    waitKey(0);
    return 0;
}

显示图像(C++)

源码:

#include <opencv2/core.hpp> //核心,基本操作库
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp> //包含输入输出的功能
#include <iostream>
using namespace cv;
using namespace std;
int main( int argc, char** argv )
{
    String imageName( "HappyFish.jpg" ); // 默认图片
    if( argc > 1) //如果输入图片名称
    {
        imageName = argv[1]; //替换掉默认图片
    }
    Mat image; //存储图像的对象
    image = imread( samples::findFile( imageName ), IMREAD_COLOR ); // 读取文件,IMREAD_COLOR>0(RGB),IMREAD_CGRAYSCALE=0(GRAY),IMREAD_UNCHANGED<0(原图)
    if( image.empty() )   //检查非法输入
    {
        cout <<  "Could not open or find the image" << std::endl ;
        return -1;
    }
    namedWindow( "Display window", WINDOW_AUTOSIZE ); // 创建窗口
    imshow( "Display window", image );//显示图片
    waitKey(0); // 等待窗口关闭
    return 0;
}

其他和文件和上一节的一致

修改和保存图像(C++)

主要就是学习cv::imread,cv::imwrite,cv::cvrColor这三个函数,和python里面的函数功能一致。分别是读取文件,保存文件,转换颜色空间。

源码

#include <opencv2/opencv.hpp>
using namespace cv;
int main( int argc, char** argv )
{
 char* imageName = argv[1];
 Mat image;
 image = imread( imageName, IMREAD_COLOR );
 if( argc != 2 || !image.data )
 {
   printf( " No image data \n " );
   return -1;
 }
 Mat gray_image;
 cvtColor( image, gray_image, COLOR_BGR2GRAY );
 imwrite( "../../images/Gray_Image.jpg", gray_image );
 namedWindow( imageName, WINDOW_AUTOSIZE );
 namedWindow( "Gray image", WINDOW_AUTOSIZE );
 imshow( imageName, image );
 imshow( "Gray image", gray_image );
 waitKey(0);
 return 0;
}

二、核心功能

学习基本构造功能,以及如何在像素级别上操作图像

Mat-基本图像容器(C++)

学习如何将图像存储在内存中以及如何将其内容打印到控制台

Mat介绍

需要了解Mat的第一件事是,不需要手动分配其内存并在不需要时立即释放它。

Mat本质上是具有两个数据部分的类:矩阵头(包含诸如矩阵大小,存储方法,存储矩阵的地址等信息)以及指向包含该矩阵的矩阵的指针像素值(根据选择的存储方法采用任何尺寸)

我们要做的最后一件事是通过不必要地复制可能较大的图像来进一步降低程序速度。

复制运算符只会将标题和指针复制到大型矩阵,而不是数据本身

存放方法(颜色空间)

  • RGB(A)
  • HSV 和 HLS :描述颜色的更自然的方式
  • YCrCb
  • CIE L a b:通常用于测量给定颜色与另一种颜色的距离

    创建Mat对象

类型指定约定:

CV_[比特位数][有符号或无符号][类型前缀]C[通道数]

复制方法(元素复制)

这里两个复制函数均是复制之后的变量完全独立,不存在共享数据。

cv::Mat::clone()

cv::Mat::copyTo()

输出格式
其他openCV对象的输出

二维点

三维点

vector

vector of point

如何使用OpenCV扫描图像,查找表和时间测量(C++)

了解如何使用OpenCV扫描图像(遍历每个图像像素)

对矩阵进行蒙版运算

了解如何使用邻居访问来扫描图像,并使用cv :: filter2D函数在图像上应用内核过滤器。

蒙版运算其实就是在原始图像上覆膜,或者可以理解为另一类的滤波操作,即提取特定的元素

所以问题来了,mask矩阵和滤波器核有什么区别呢?—貌似没啥区别

这里官方的教程个人感觉更偏滤波一些。而且其python的代码风格也有C++非常类似,举的例子也是锐化图像的例子:

from __future__ import print_function
import sys
import time
import numpy as np
import cv2 as cv
def is_grayscale(my_image): #判断是否是灰度图
    return len(my_image.shape) < 3
def saturated(sum_value): #保证计算后的值范围在0-255之间
    if sum_value > 255:
        sum_value = 255
    if sum_value < 0:
        sum_value = 0
    return sum_value
def sharpen(my_image):
    if is_grayscale(my_image):
        height, width = my_image.shape
    else:
        my_image = cv.cvtColor(my_image, cv.CV_8U)
        height, width, n_channels = my_image.shape
    result = np.zeros(my_image.shape, my_image.dtype)
    #滤波操作
    for j in range(1, height - 1):
        for i in range(1, width - 1):
            if is_grayscale(my_image):
                sum_value = 5 * my_image[j, i] - my_image[j + 1, i] - my_image[j - 1, i] \
                            - my_image[j, i + 1] - my_image[j, i - 1]
                result[j, i] = saturated(sum_value)
            else:
                for k in range(0, n_channels):
                    sum_value = 5 * my_image[j, i, k] - my_image[j + 1, i, k]  \
                                - my_image[j - 1, i, k] - my_image[j, i + 1, k]\
                                - my_image[j, i - 1, k]
                    result[j, i, k] = saturated(sum_value)
    
    return result
def main(argv):
    filename = 'lena.jpg'
    img_codec = cv.IMREAD_COLOR
    if argv:
        filename = sys.argv[1]
        if len(argv) >= 2 and sys.argv[2] == "G":
            img_codec = cv.IMREAD_GRAYSCALE
    src = cv.imread(cv.samples.findFile(filename), img_codec)
    if src is None:
        print("Can't open image [" + filename + "]")
        print("Usage:")
        print("mat_mask_operations.py [image_path -- default lena.jpg] [G -- grayscale]")
        return -1
    cv.namedWindow("Input", cv.WINDOW_AUTOSIZE)
    cv.namedWindow("Output", cv.WINDOW_AUTOSIZE)
    cv.imshow("Input", src)
    t = round(time.time())
    dst0 = sharpen(src)
    t = (time.time() - t)
    print("Hand written function time passed in seconds: %s" % t)
    cv.imshow("Output", dst0)
    cv.waitKey()
    t = time.time()
    
    kernel = np.array([[0, -1, 0],
                       [-1, 5, -1],
                       [0, -1, 0]], np.float32)  # kernel should be floating point type
    
    dst1 = cv.filter2D(src, -1, kernel)
    # ddepth = -1, means destination image has depth same as input image
    
    t = (time.time() - t)
    print("Built-in filter2D time passed in seconds:     %s" % t)
    cv.imshow("Output", dst1)
    cv.waitKey(0)
    cv.destroyAllWindows()
    return 0
if __name__ == "__main__":
    main(sys.argv[1:])

其中的锐化操作可以用 filter2D() 来简化,主体内容简化后内容类似下面:
#import的库与上面的代码相同
src = cv.imread("test.jpg")
kernel = np.array([[0, -1, 0],
                   [-1, 5, -1],
                   [0, -1, 0]], np.float32)

dst1 = cv.filter2D(src, -1, kernel)#input image, depth, kerne(卷积核)
cv.namedWindow("Input", cv.WINDOW_AUTOSIZE)
cv.namedWindow("Output", cv.WINDOW_AUTOSIZE)
cv.imshow("Input", src)
cv.imshow("Output", dst1)
cv.waitKey(0)
cv.destroyAllWindows()
# ddepth = -1, means destination image has depth same asinput image

图像操作

从文件读取/写入图像,访问像素,原始操作,可视化图像。

使用OpenCV添加(混合)两个图像

将学习如何融合两个图像!

改变图像的对比度和亮度!

将学习如何更改图像外观!

离散傅立叶变换

了解如何以及为什么在OpenCV中使用离散傅立叶变换

使用XML和YAML文件的文件输入和输出

如何使用OpenCV的cv :: FileStorage数据结构将数据写入和读取XML或YAML文件格式

如何使用OpenCV parallelfor并行化代码(C++)

如何使用OpenCV parallelfor轻松并行化代码。

三、图像处理

了解OpenCV内部的图像处理(操作)功能。

1基本图纸

学习如何使用OpenCV绘制简单的几何图形

2带有OpenCV的随机生成器和文本

使用OpenCV绘制一些精美的东西

3平滑图像

一些基本的线性滤波器

4腐蚀和膨胀

改变物体的形状

5更多形态转换

研究不同的形态运算符

6命中或缺失

如何使用“命中或缺失”操作在二进制图像中查找图案

7使用形态学运算提取水平线和垂直线

如何使用不同的形态运算符来提取水平线和垂直线

8影像金字塔

需要更大/或更小的图像怎么办

9基本阈值操作

确定保留哪些像素了

10使用inRange的阈值操作

使用inRange函数的阈值操作。

11制作自己的线性滤波器!

学习使用OpenCV函数设计自己的过滤器

12为图像添加边框

学习如何填充图像

13Sobel衍生物

学习如何计算渐变并使用它们来检测边缘

14拉普拉斯算子

了解Laplace运算符以及如何使用它检测边缘

15坎尼边缘检测器

学习检测边缘的复杂方法

16霍夫线变换

学习如何检测线

17霍夫圆变换

学习如何检测圈子

18重新映射

学习如何操纵像素位置

19仿射变换

学习如何旋转,平移和缩放图像

20直方图均衡

学习如何改善图像的对比度

21直方图计算

学习如何创建和生成直方图

22直方图比较

学习计算直方图之间的指标

23背投

学习如何使用直方图在图像中找到相似的对象

24模板匹配

学习如何匹配图像中的模板

25在图像中寻找轮廓

学习如何在图像中找到对象的轮廓

26凸包

学习如何获取船体轮廓并绘制它们

27为轮廓创建边界框和圆

学习如何获取轮廓的边界框和圆

28创建轮廓的边界旋转框和椭圆

学习如何获取轮廓的旋转边界框和椭圆

29影像时刻

学习计算图像时刻的地方

30点多边形测试

学习如何计算从图像到轮廓的距离

31基于距离变换和分水岭算法的图像分割

学习使用拉普拉斯滤波,距离变换和分水岭算法对对象进行分割。

32离焦去模糊滤镜

学习如何通过维纳滤镜恢复散焦图像。

33运动去模糊滤波器

学习如何使用维纳滤镜恢复运动模糊失真的图像。

34梯度结构张量的各向异性图像分割

学习如何通过梯度结构张量分割具有单个局部方向的各向异性图像。

35周期性除噪滤波器

学习如何消除傅立叶域中的周期性噪声。

四、高级GUI和媒体

如何使用库的内置图形用户界面的有价值的教程。

在程序中添加跟踪栏

将学习如何在应用程序中添加跟踪栏

五、图像输入和输出

如何使用imgcodecs模块读取和写入图像。

使用GDAL读取地理空间栅格文件

读取常见的GIS Raster和DEM文件以显示和处理地理数据。

六、视频输入和输出

如何使用videio模块读取和写入视频。

具有OpenCV和相似度测量的视频输入

学习如何读取视频流,以及如何计算相似度值,例如PSNR或SSIM。

使用OpenCV创建视频

使用Kinect和其他OpenNI兼容的深度传感器

使用Creative Senz3D和其他兼容Intel Perceptual Computing SDK的深度传感器

七、相机校准和3D重建

如何从2D图像中找出3D世界信息。

创建校准图案

学习如何创建一些校准图案。

用方形棋盘进行相机校准

使用一些棋盘图像来校准相机。

使用OpenCV进行相机校准

通过使用棋盘,圆圈或不对称圆圈图案进行相机校准

纹理对象的实时姿态估计

使用ORB功能,基于FlannBased的匹配器,PnP方法以及Ransac和线性卡尔曼滤波器对纹理对象的实时姿态估计,可以拒绝可能的不良姿态。

交互式相机校准应用

通过使用棋盘,chAruco,不对称圆圈或双重不对称圆圈图案进行相机校准

八、2D功能框架

如何使用OpenCV中的特征点检测器,描述符和匹配框架的信息。

哈里斯拐角探测器

为什么跟踪拐角是个好主意?我们将学习如何使用Harris方法来检测角点。

Shi-Tomasi拐角检测器

在这里我们使用一种改进的方法来更准确地检测拐角。

创建自己的角落探测器

在这里,您将学习如何使用OpenCV功能制作个性化的角检测器!

检测子像素中的角位置

像素分辨率够吗?在这里,我们学习了一种提高角点定位精度的简单方法。

特征检测

在本教程中,您将使用features2d检测兴趣点。

功能说明

在本教程中,您将使用features2d计算特征向量。

与FLANN的功能匹配

在本教程中,您将使用FLANN库进行快速匹配。

2D +全息照相法查找已知物体

在本教程中,您将使用features2d和calib3d来检测场景中的对象。

检测平面物体

您将使用features2d和calib3d模块来检测场景中已知的平面对象。

AKAZE本地特征匹配

使用AKAZE局部特征查找两个图像之间的对应关系。

AKAZE和ORB平面跟踪

使用AKAZE和ORB进行平面物体跟踪。

用代码解释单应性的基本概念

本教程将通过一些演示代码解释单应性的基本概念。

九、视频分析

用于视频流的算法,例如运动提取,特征跟踪和前景提取。

如何使用背景减法

我们将学习如何从视频和图像序列中提取前景蒙版并显示它们。

Meanshift和Camshift

了解如何使用Meanshift和Camshift算法跟踪视频中的对象。

光流

将学习如何使用光流方法来跟踪稀疏特征或创建密集表示。

十、对象检测

检测人脸

级联分类器

在这里,我们学习如何使用objdetect在我们的图像或视频中查找对象

级联分类器训练

本教程描述了opencv_traincascade应用程序及其参数。

十一、深度神经网络

展示了如何有效地使用dnn模块。

加载Caffe框架模型

在本教程中,您将学习如何使用来自Caffe模型动物园的GoogLeNet训练的网络,将opencv_dnn模块用于图像分类。

如何启用卤化物后端以提高效率

本教程指导如何使用Halide语言后端在OpenCV深度学习模块中运行模型。

如何为您的Halide后端安排网络

在本教程中,我们描述了使用OpenCV深度学习模块中的Halide后端调度网络的方法。

如何在Android设备上运行深度网络

本教程将向您展示如何在Android设备上使用OpenCV运行深度学习模型。

YOLO DNN

在本教程中,您将学习如何通过yolo_object_detection和设备捕获,视频文件或图像使用opencv_dnn模块。

如何在浏览器中运行深度网络

在本教程中,我们将使用OpenCV.js在浏览器中运行深度学习模型。

自定义深度学习层支持

如何定义自定义图层以导入网络。

十二、机器学习

使用功能强大的机器学习类进行统计分类,数据回归和聚类。

支持向量机简介

了解什么是支持向量机。

支持向量机用于非线性可分离数据

在这里,您将学习在无法线性分离训练数据时如何定义SVM的优化问题

主成分分析(PCA)简介

了解什么是主成分分析(PCA)

十三、Graph API

了解如何使用图形API(G-API)和从“传统” OpenCV到图形模型的端口算法

十四、计算摄影

使用OpenCV进行高级照片处理。

高动态范围成像

了解如何创建和处理高动态范围图像。

十五、图像拼接

了解如何使用OpenCV缝合管线创建美丽的照片全景图以及其他内容。

高级拼接API(Stitcher类)

您将使用高级拼接API创建照片全景。您将了解Stitcher类及其配置。

十六、GPU加速

利用视频卡的功能来运行OpenCV算法,从系统中挤出几乎所有的计算能力。

GPU上的相似性检查(PNSR和SSIM)

用推力使用cv :: cuda :: GpuMat

十七、Opencv ios

参考文献

[1] OpenCV学习教程

[2] 在linux上正确的姿势安装OpenCV

[3] ubuntu16.04下载opencv3.4.0并检测是否安装成功


Author: star
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source star !
  TOC