OpenCV 简单入门
环境搭建
- 下载OpenCV库
https://opencv.org/releases/- 设置引用目录
\opencv\sources\include\opencv2- 设置库目录(我用的x64的)
\opencv\build\x64\vc14\lib
基础讲解
cv::Mat 矩阵类型
Mat中还含有每个像素的像素值图像文件格式
CV_8UC1,CV_8UC2,CV_8UC3 等等
含义是:8U 8bit的unsigned类型,CX指几个通道读取文件
cv::Mat img = cv::imread(“C:/test.jpg”);新建一个显示窗口
cv::namedWindow(“测试”, cv::WINDOW_AUTOSIZE);在“测试”这个窗口输出图片。
cv::imshow(“测试”, img);
入门代码
// openvcFirst.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
#pragma comment(lib,"opencv_world411d.lib")
int main()
{
//读取文件
cv::Mat img = cv::imread("C:/test.jpg");
if (img.empty()) {
printf_s("找不到图片\n");
return -1;
}
/*
flag 可以选
WINDOW_AUTOSIZE 窗口大小自动适应图片大小,并且不可手动更改。(上面图1就是使用的它)
WINDOW_NORMAL 用户可以改变这个窗口大小
WINDOW_OPENGL 窗口创建的时候会支持OpenGL
*/
cv::namedWindow("测试", cv::WINDOW_AUTOSIZE);//新建一个显示窗口
cv::imshow("测试", img);//在“测试”这个窗口输出图片。
cv::waitKey(2000); //等待2秒
cv::Mat output;
//Convert Color
cv::cvtColor(img, output, cv::COLOR_BGR2GRAY);//将img的bgr转为灰色 存到output
cv::imshow("测试", output);//显示output
cv::waitKey(5000);//等待5秒
cv::Mat output2;
output2 = cv::Scalar(255,255,255);//rgb颜色 会将output2 画成一个纯色图
cv::imshow("测试", output2);//显示output2
cv::waitKey(5000);//等待5秒
cv::imwrite("d:/test.jpg", output);//保存output到test.jpg
}
掩膜操作
cv::Mat img = cv::imread("C:/test.jpg");
if (img.empty()) {
printf_s("找不到图片\n");
return -1;
}
cv::namedWindow("测试", cv::WINDOW_AUTOSIZE);//新建一个显示窗口
cv::imshow("测试", img);//在“测试”这个窗口输出图片。
cv::waitKey(2000);
cv::Mat BGR(1080, 1920, CV_8UC3, cv::Scalar(0, 180, 255));
cv::imshow("测试", BGR);
cv::waitKey(2000);
cv::Mat output = cv::Mat::zeros(img.size(), img.type());//用来存储修改过的
//获取像素指针
/*
Mat.ptr<uchar>(int i=0) //获取像素矩阵的指针,索引i表示第几行,从0开始
P(row,col) //获取当前像素点 P(row,col) = Mat.ptr<uchar>(row)[col]
//说白了就是个二维矩阵,程序里可以说是2级指针
矩阵的掩膜操作
根据掩膜重新计算每个像素的像素值 可以提高图像的对比度
对比度公式
img(row,col) = 5 * img(row,col)-[img(row-1,col)+img(row+1,col)+img(row,col-1)+img(row,col+1)]
类似这样:
0 -1 0
-1 5 -1
0 -1 0
*/
//我们现在就是手动的进行卷积运算,下面还有API可以很方便的操作
//img.cols 就是宽度 1920,channels就是3,代表3个通道 rgb
//*3的原因是我们获取到的其实是uchar 所以是8个bit,每个像素rgb是24bit(r、g、b各占8bit),所以我们需要*通道数
int cols = (img.cols - 1) * img.channels();
int rows = img.rows;
int channels = img.channels();
for (int row = 1; row < rows - 1; row++) {
const uchar* previous = img.ptr<uchar>(row - 1);//上一行
const uchar* current = img.ptr<uchar>(row);//当前行
const uchar* next = img.ptr<uchar>(row + 1);//下一行
uchar* outputCurrent = output.ptr<uchar>(row);//用于输出的
for (int col = channels; col < cols; col++) {
//保存到输出mask中
/*
saturate_cast<uchar> 就是最小不低于0 最大不超过255
saturate_cast<type> 就是取type的最小或最大值,不能超过范围
类似 math.max(math.min(value,255),0)
*/
outputCurrent[col] = cv::saturate_cast<uchar>(5 * current[col] - (current[col - channels] + current[col + channels] + previous[col] + next[col]));
}
}
std::cout << img.size() << "changed!\n";
cv::imshow("测试", output);
cv::waitKey(2000);
用filter2D实现
下面这个效果相同,filter2D 就可以实现上面复杂的操作
//filter2D 默认锚点为-1,-1
cv::Mat kernel = (cv::Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
//img.depth() 位图深度 enum{CV_8U=0,CV_8S=1,CV_16U=2,CV_16S=3,CV_32S=4,CV_32F=5,CV_64F=6}
cv::filter2D(img, output, img.depth(), kernel);
cv::imshow("测试", output);//在“测试”这个窗口输出图片。
cv::waitKey(2000);
3通道转4通道(也就是带透明度的图片)
Mat src = imread("C:/test.jpg");
vector<Mat> rgb3Channels(3); //申请一个mat的vector 用来存放split后的矩阵信息
split(src, rgb3Channels);//将src进行分割,并存放在rgb3Channels
Mat zero_mat= Mat::zeros(Size(src.cols, src.rows), CV_8UC1); //申请一个单通道全0矩阵
vector<Mat> channels_4; //为merge做准备
//注意 顺序是bgr
channels_4.push_back(rgb3Channels[0]); //b 这里存放的属于 src整个矩阵所有的b信息,下面相同
channels_4.push_back(rgb3Channels[1]); //g
channels_4.push_back(rgb3Channels[2]); //r
channels_4.push_back(zero_mat); //alpha=0
Mat img_alpha_0;
merge(channels_4, img_alpha_0); //channels_4是我们组合好的,但它是vector,我们需要合并,其实就是对应split的原理,说白了就是转成4通道矩阵
imshow("img_alpha_0", img_alpha_0);
waitKey(0);
常用API
- 亮度对比度调节
公式:
float alpha = 1.2 //对比度
float beta = 30 //亮度
dst.at(row,col)[0] = saturate_cast(srcB * alpha + beta)
- 均值模糊
blur(Mat src,Mat dst,Size(x,y),Point(-1,-1));
Size其实是kernel的大小,不是图像大小
Point(-1,-1) 锚点位置
- 高斯模糊
GaussianBlur(Mat src,Mat dst,Size(x,y),sigmax,sigmay);
- putText 文字
- line 画线
- rectangle 方框
- ellipse 椭圆
- circle 圆圈
- fillPoly 填充
- 线性混合
f0为第一张图像,f1为第二章图像
x为像素
当x变化时,让2张图片的像素值相加,取值范围在1-0
void cv::addWeighted(
InputArray src1, //图像1
double alpha, //图像1的alpha值
InputArray src2,//图像2
double beta,//图像2的alpha直 ,一般是用(1-第一张图的alpha)来算
double gamma,//gamma值
InputArray dst, //用来保存输出的图像
int dtype = -1//输出混合图像
)
计算原理就是
dst[i] = saturate_cast(src1[i] * alpha + src2[i] * beta + gamma)
还有add,multiply等方法,建议不要使用,效果非常差