imuncle / imuncle.github.io

大叔的个人小站
https://imuncle.github.io/
78 stars 17 forks source link

OpenCV基础知识 #95

Open imuncle opened 4 years ago

imuncle commented 4 years ago

CMakeLists配置

cmake_minimum_required (VERSION 2.8)
include_directories(${OpenCV_INCLUDE_DIRS}) #OpenCV的include文件夹
set(OpenCV_DIR /usr/local/lib) #OpenCV的lib文件夹
find_package(OpenCV REQUIRED)
add_executable(程序名 主函数所在cpp)
target_link_libraries(程序名 ${OpenCV_LIBS})

显示图像

#include <opencv2/opencv.hpp>
using namespace cv;

void main()
{
    Mat src = imread("../test.jpg");
    imshow("【图片显示】", src);
    waitKey(0); //等待任意键按下
}

图像腐蚀

Mat src = imread("../test.jpg");
// OpenCV创建形态学处理的内核:MORPH_ELLIPSE、MORPH_CROSS、MORPH_RECT
Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));  //创建腐蚀内核
Mat dst;
erode(src, dst, element);   //腐蚀
imshow("【腐蚀效果图】", dst);

图像模糊

Mat src = imread("../test.jpg");
Mat dst;
blur(src, dst, Size(7, 7)); //均值滤波
imshow("【图像模糊】", dst);

canny边缘检测

Mat src = imread("../test.jpg");
Mat dst, edge, gray;
dst.create(src.size(), src.type()); //创建一个与src同类型和大小的矩阵
cvtColor(src, gray, COLOR_BGR2GRAY);    //转为灰度图
blur(gray, edge, Size(3, 3));
Canny(edge, edge, 3, 9, 3); //Canny边缘检测
imshow("【Canny边缘检测】", edge);

视频操作

VideoCapture capture("../1.avi");
while(1)
{
    Mat frame;
    capture>>frame; //读取当前帧
    imshow("【读取视频】", frame);
    waitKey(30);
}
VideoCapture capture(0);
while(1)
{
    Mat frame;
    capture>>frame; //读取当前帧
    imshow("【读取视频】", frame);
    waitKey(30);
}

创建窗口

// flags: WINDOW_NORMAL; WINDOW_AUTOSIZE; WINDOW_OPENGL
void namedWindow(const string& winname, int flags=WINDOW_AUTOSIZE)

保存图像

bool imwrite(const string& filename, InputArray img, const vector<int>& params=vector<int>());

imwrite("生成的图片.jpg", img);  //img为Mat对象

滑动条的创建和使用

创建函数原型:

// value:表示滑块的位置
// count:滑块可以达到的最大位置
// userdata:传给回调函数的数据,用来处理轨迹条时间,如果value是全局变量,则不用管userdata
int createTrackbar(const string& trackname, const string& winname, int* value, int count, TrackbarCallback onchange=0, void* userdata=0);

示例:

//第一个参数是轨迹条位置,第二个参数是用户数据
void on_Trackbar(int position, void* userdata)
{
    printf("position: %d\n", position);
    printf("userdata: %d\n", userdata);
}

int main()
{
    createTrackbar("透明值:", "【滑动条】", 0, 100, on_Trackbar, 1);
}

鼠标操作

指定鼠标操作消息回调函数的函数:

void setMouseCallback(const string& winname, MouseCallback onMouse, void* userdata = 0)

示例:

// flags是EVENT_FLAG的组合
void on_MouseHandle(int event, int x, int y, int flags, void* param)
{
    swith(event)
    {
        case EVENT_MOUSEMOVE:
        {
            //鼠标移动事件
        }break;
        case EVENT_LBUTTONDOWN:
        {
            //左键按下
        }break;
        case EVENT_LBUTTONUP:
        {
            //左键抬起
        }break;
        default:;
    }
}

int main()
{
    Mat src = imread("../test.jpg");
    setMouseCallback("【鼠标操作】", on_MouseHandle, (void*)&src);
    waitKey(0);
}

创建Mat对象的方法

使用Mat()构造函数

Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255));

// CV_[位数][带符号与否][类型前缀]C[通道数]

通过构造函数进行初始化

int sz[3] = {2, 2, 2};
Mat L(3, sz, CV_8UC, Scalar::all(0));

利用creat()函数

M.create(4, 4, CV_8UC2);

注意:此创建方法不能为矩阵设置初值,只是在改变尺寸时重新为矩阵数据开辟内存而已

采用MATLAB式的初始化方式

Mat E = Mat::eye(4, 4, CV_64F);

Mat O = Mat::ones(2, 2, 2CV_32F);

Mat Z = Mat::zeros(3, 3, CV_8CU1);

逗号分隔式初始化函数

Mat C = (Mat_<double>(3, 3) << 0, -1, 0, -1, -5, -1, 0, -1, 0);

常用数据结构和函数

Point类

Point point;
point.x = 10;
point.y = 8;

Point point = Point(10, 8);

Scalar类

Scalar(a, b, c);    //BGR

cvtColor()函数

void cvtColor(InputArray src, OutputArray dst, int code, int dstCn = 0)

计时函数

Mat类

Mat类有若干成员函数可以获取图像的属性。工友成员变量cols和rows给出了图像的宽和高,channels()返回图像的通道数

图像混合

// 定义一个Mat类型并给其设定ROI区域
Mat imageROI;
imageROI = image(Rect(500, 250, logo.cols, logo.rows));

addWeighted(srcImage1, alphaValue, srcImage2, betaValue, 0.0, dstImage);
void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype = -1)

// dst = src1[I]*alpha + src2[I]*beta + gamma

颜色通道分离、混合

split()函数

Mat src = imread("../test.jpg");
vector<Mat> channels;
split(src, channels);
// 可以通过channels.at()访问各个通道

merge()

void merge(const Mat* mv, size_t count, OutputArray dst);
void merge(const vector<Mat>& mv, OutputArray dst );

线性滤波

均值滤波

// dst需要有和src一样的尺寸和类型
void blur(InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1, -1), int borderType = BORDER_DEFAULT)
blur(image, out, Size(7, 7));

高斯滤波

// dst需要有和src一样的尺寸和类型
// sigmaY=0时,就将它设为sigmaX
void GuassianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType = BORDER_DEFAULT)
GaussianBlur(image, out, Size(3, 3), 0, 0);

非线性滤波

中值滤波

// dst需要有和src一样的尺寸和类型
// ksize必须是大于1的奇数
void medianBlur(InputArray src, OutputArray dst, int ksize)

双边滤波

// dst需要有和src一样的尺寸和类型
// d是过滤过程中每个像素领域的直径
// sigmaColor是颜色空间滤波器的sigma值
// sigmaSpace是坐标空间滤波器的sigma值
void bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType = BORDER_DEFAULT)
bilateralFilter(image, out, 25, 25*2, 25/2);

形态学滤波

核心API函数:morphologyEx()

void morphologyEx(
    InputArray src,
    OutputArray dst,
    int op,
    InputArray kernel,
    Point anchor = Point(-1, -1),
    int iterations = 1,
    int borderType = BORDER_CONSTANT,
    const Scalar& borderValue = morphologyDefaultBorderValue()
);
标识符op 含义
MORPH_OPEN 开运算
MORPH_CLOSE 闭运算
MORPH_GRADIENT 形态学梯度
MORPH_TOPHAT 顶帽
MORPH_BLACKHAT 黑帽
MORPH_ERODE 腐蚀
MORPH_DILATE 膨胀

膨胀

void dilate(
    InputArray src,
    OutputArray dst,
    InputArray kernel,  //内核,一般用getStructuringElement获取
    Point anchor = Point(-1, -1);
    int iterations = 1, //迭代次数
    int borderType = BORDER_CONSTANT,
    const Scalar& borderValue = morphologyDefaultBorderValue()
);
Mat image = imread("../test.jpg");
Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
Mat out;
dilate(image, out, element);

腐蚀

void erode(
    InputArray src,
    OutputArray dst,
    InputArray kernel,  //内核,一般用getStructuringElement获取
    Point anchor = Point(-1, -1);
    int iterations = 1, //迭代次数
    int borderType = BORDER_CONSTANT,
    const Scalar& borderValue = morphologyDefaultBorderValue()
);
Mat image = imread("../test.jpg");
Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
Mat out;
erode(image, out, element);

开运算

先腐蚀后膨胀

morphologyEx(src, dst, MORPH_OPEN, element);

闭运算

先膨胀后腐蚀

morphologyEx(src, dst, MORPH_CLOSE, element);

形态学梯度

膨胀图与腐蚀图之差

morphologyEx(src, dst, MORPH_GRADIENT, element);

顶帽

原图像与开运算结果图之差

morphologyEx(src, dst, MORPH_TOPHAT, element);

黑帽

闭运算结果图与原图像之差

morphologyEx(src, dst, MORPH_BLACKHAT, element);

图像尺寸调整

//若dsize为0,则由fx和fy计算
//若fx, fy为0,则由dsizez计算
void resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR)

阈值化

固定阈值操作

Threshold()对单通道数组应用固定阈值操作。

double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)
threshold(gray_image, dst, thresholdValue, 255, THRESH_BINARY)

自适应阈值操作

void adaptiveThreshold(InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C)

边缘检测

canny算子

void Canny(InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize = 3, bool L2gradient = false)

sobel算子

void Sobel(
    InputArray src,
    OutputArray dst,
    int ddepth, //输出图像的深度
    int dx, //x方向上的差分阶数
    int dy, //y方向上的差分阶数
    int ksize = 3,  //Sobel核的大小,必须取1/3/5/7
    double scale = 1,
    double delta = 0,
    int borderType = BORDER_DEFAULT
);

Laplacian算子

void Laplacian(
    InputArray src,
    OutputArray dst,
    int ddepth,
    int ksize = 1,
    double scale = 1,
    double delta = 0,
    int borderType = BORDER_DEFAULT
);

霍夫变换

void HoughLines(
    InputArray image,
    OutputArray lines,
    double rho,
    double theta,
    int threshold,
    double srn=0,
    double stn=0
);

寻找轮廓findContours()函数

在二值图像中寻找轮廓

void findContours(
    InputArray image,   //图像需为8位单通道图像
    OutputArrayOfArrays contours,
    OutputArray hierarchy,
    int mode,   //RETR_EXTERNAL只检测最外层轮廓;RETR_LIST提取所有轮廓,不建立等级关系;RETR_CCOMP提取所有轮廓,组织为双层结构;RETR_TREE提取所有轮廓,建立网状的轮廓结构
    int method, //轮廓的近似方法:CHAIN_APPROX_NONE获取每个轮廓的每个像素;CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标
    Point offset = Point()
);

常与drawContours配合使用

void drawContours(
    InputArray image,
    InputArrayOfArrays contours,
    int contourIdx,
    const Scalar& color,
    int thickness = 1,
    int lineType = 8,
    InputArrayhierarchy = noArray(),
    int maxLevel = INT_MAX,
    Point offset = Point()
);

示例:

vector<vector<Point>> contours;
vector<Vec4i> hierarchy;

findContours(src, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);

int index = 0;
for(;index >= 0; index = hierarchy[index][0])
{
    Scalar color(rand()&255, rand()&255, rand()&255);
    drawContours(dst, contours, index, color, FILLED, 8, hierarchy);
}