1.学习资料
复制这段内容后打开百度网盘App,操作更方便哦。
链接:https://pan.baidu.com/s/1mnGmwjsNizmmdD0D8sFJHw
提取码:2Mrv --来自百度网盘超级会员V5的分享
2.第0节课
开发环境搭建
包括头文件:
D:\opencv3.1\opencv\build\include
D:\opencv3.1\opencv\build\include\opencv
D:\opencv3.1\opencv\build\include\opencv2
库文件
D:\opencv3.1\opencv\build\x64\vc14\lib
链接器
opencv_world310d.lib
#include <opencv2/core/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** args) {
//Mat image = imread("girl.jpg", IMREAD_GRAYSCALE);
Mat image = imread("D:/code/vproject/timg.jpg");
if (image.empty()) {
cout << "could not find the image resource..." << std::endl;
return -1;
}
namedWindow("My Image", CV_WINDOW_AUTOSIZE);
imshow("My Image", image);
waitKey(0);
return 0;
}
3.第1节课
(1)加载图片(cv::imread)
imread功能是加载图像文件成为一个Mat对象,其中第一个参数表示图像文件名称
第二个参数,表示加载的图像是什么类型,支持常见的三个参数值
l IMREAD_UNCHANGED (<0) 表示加载原图,不做任何改变l IMREAD_GRAYSCALE ( 0) 表示把原图作为灰度图像加载进来l IMREAD_COLOR (>0) 表示把原图作为 RGB 图像加载进来注意:OpenCV支持JPG、PNG、TIFF等常见格式图像文件加载
以加载灰度图像为例:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
using namespace std;
int main(int argc, char** args) {
//Mat image = imread("girl.jpg", IMREAD_GRAYSCALE);
Mat image = imread("D:/code/vproject/timg.jpg", IMREAD_GRAYSCALE);
if (image.empty()) {
cout << "could not find the image resource..." << std::endl;
return -1;
}
namedWindow("My Image", CV_WINDOW_AUTOSIZE);
imshow("My Image", image);
waitKey(0);
return 0;
}
(2)修改图片(cv::cvtColor)
cvtColor的功能是把图像从一个彩色空间转换到另外一个色彩空间,有三个参数,
第一个参数表示源图像、
第二参数表示色彩空间转换之后的图像、
第三个参数表示源和目标色彩空间如:COLOR_BGR2HLS 、COLOR_BGR2GRAY 等
cvtColor( image, gray_image, COLOR_BGR2GRAY );
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
using namespace std;
int main(int argc, char** args) {
//Mat image = imread("girl.jpg", IMREAD_GRAYSCALE);
//Mat image = imread("D:/code/vproject/timg.jpg", IMREAD_GRAYSCALE);
Mat image = imread("D:/code/vproject/timg.jpg");
if (image.empty()) {
cout << "could not find the image resource..." << std::endl;
return -1;
}
namedWindow("My Image", CV_WINDOW_AUTOSIZE);
imshow("My Image", image);
namedWindow("Out", CV_WINDOW_AUTOSIZE);
Mat out;
cvtColor(image, out, CV_RGB2GRAY);
imshow("Out", out);
waitKey(0);
return 0;
}
(3)保存图片(cv::imwite)
保存图像文件到指定目录路径
只有8位、16位的PNG、JPG、Tiff文件格式而且是单通道或者三通道的BGR的图像才可以通过这种方式保存
保存PNG格式的时候可以保存透明通道的图片
可以指定压缩参数
imwrite("D:/hlstest.png", out);
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
using namespace std;
int main(int argc, char** args) {
//Mat image = imread("girl.jpg", IMREAD_GRAYSCALE);
//Mat image = imread("D:/code/vproject/timg.jpg", IMREAD_GRAYSCALE);
Mat image = imread("D:/code/vproject/timg.jpg");
if (image.empty()) {
cout << "could not find the image resource..." << std::endl;
return -1;
}
namedWindow("My Image", CV_WINDOW_AUTOSIZE);
imshow("My Image", image);
namedWindow("Out", CV_WINDOW_AUTOSIZE);
Mat out;
cvtColor(image, out, CV_BGR2HLS);
imshow("Out", out);
imwrite("D:/hlstest.png", out);
waitKey(0);
return 0;
}
4.第2节课
(1)获取图像像素指针
Mat.ptr<uchar>(int i=0)
获得当前行指针const uchar* current= myImage.ptr<uchar>(row );
获取当前像素点P(row, col)的像素值 p(row, col) =current[col]
(2)掩码操作解释
1.手写函数
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
using namespace std;
int main(int argc, char** args) {
Mat src, dst;
src = imread("D:/code/vproject/car-1.jpg");
if (!src.data) {
printf("could not load image..\n");
return -1;
}
namedWindow("inputimage", CV_WINDOW_AUTOSIZE);
imshow("inputimage", src);
/*clos表示列数,
其中src.channels():通道,RGB有3个颜色
*/
int cols = (src.cols - 1) * src.channels();
//offsetx = 3
int offsetx = src.channels();
//rows 表示行数
int rows = src.rows;
//初始化dst,将src的值赋给dst
//dst = Mat::zeros(src.size(), src.type());
//zeros(src.size(), src.type()) 和src的大小相同但是是:黑色的图片
//初始化也能如下所示
src.copyTo(dst);
/*因为掩码需要上一行的数据,则从第1行还是遍历
又因为掩码需要下一行的数据,则倒数第二行就停止遍历*/
for (int row = 1; row < (rows - 1); row++) {
//previous表示上一行的RGB值
//current表示当前行的RGB值
//next表示下一行的RGB值
const uchar* previous = src.ptr<uchar>(row - 1);
const uchar* current = src.ptr<uchar>(row);
const uchar* next = src.ptr<uchar>(row + 1);
uchar* output = dst.ptr<uchar>(row);
for (int col = offsetx; col < cols; col++) {
/*颜色的排列是 RGB(red green blue)那么同行相减应该是同颜色相减
即:减去一个通道间隔的颜色- offsetx
saturate_cast<uchar>(int i):规范颜色在0~255
*/
output[col] = saturate_cast<uchar>(5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col]));
}
}
namedWindow("contrast image demo", CV_WINDOW_AUTOSIZE);
imshow("constrast image demo", dst);
waitKey(0);
return 0;
}
使得处理后的值没有负数或者超过255的数字,规范颜色
像素范围处理saturate_cast<uchar>
saturate_cast<uchar>(-100),返回 0。
saturate_cast<uchar>(288),返回255
saturate_cast<uchar>(100),返回100
这个函数的功能是确保RGB值得范围在0~255之间
2.函数实现:filter2D
filter2D( src, dst, src.depth(), kernel );其中src与dst是Mat类型变量、src.depth表示位图深度,有32、24、8等
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
using namespace std;
int main(int argc, char** args) {
Mat src, dst;
src = imread("D:/code/vproject/car-1.jpg");
if (!src.data) {
printf("could not load image..\n");
return -1;
}
namedWindow("inputimage", CV_WINDOW_AUTOSIZE);
imshow("inputimage", src);
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(src, dst, src.depth(), kernel);
namedWindow("contrast image demo", CV_WINDOW_AUTOSIZE);
imshow("constrast image demo", dst);
imwrite("D:/code/vproject/car-1-掩码.jpg", dst);
waitKey(0);
return 0;
}
3.查看时间消耗
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
using namespace std;
int main(int argc, char** args) {
Mat src, dst;
src = imread("D:/code/vproject/car-1.jpg");
if (!src.data) {
printf("could not load image..\n");
return -1;
}
namedWindow("inputimage", CV_WINDOW_AUTOSIZE);
imshow("inputimage", src);
double t = getTickCount();
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(src, dst, src.depth(), kernel);
double timeconsume = (getTickCount() - t) / getTickFrequency();
printf("time consume %.2f", timeconsume);
namedWindow("contrast image demo", CV_WINDOW_AUTOSIZE);
imshow("constrast image demo", dst);
imwrite("D:/code/vproject/car-1-掩码.jpg", dst);
waitKey(0);
return 0;
}
double t = getTickCount();
double timeconsume = (getTickCount() - t) / getTickFrequency();
printf("time consume %.2f", timeconsume);
5.第3节课
(1)Mat对象与IpIimage
Mat对象:头部与数据部分
(2)Mat对象使用
1.复制图片相关
Mat src;
src = imread("D:/code/vproject/car-1.jpg");(1)Mat dst = Mat(src.size(), src.type());
//把dst的颜色设置为(127, 0, 255)
dst = Scalar(127, 0, 255);(2)直接全部克隆
Mat clone = src.clone();(3)复制图像:copyTo
Mat copy;
src.copyTo(copy);
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat src;
src = imread("D:/code/vproject/car-1.jpg");
if (src.empty()) {
cout << "could not load image..." << endl;
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
Mat dst;
dst = Mat(src.size(), src.type());
//把dst的颜色设置为(127, 0, 255):玫红色
dst = Scalar(127, 0, 255);
namedWindow("output", CV_WINDOW_AUTOSIZE);
imshow("output", dst);
//直接全部克隆
Mat clone = src.clone();
namedWindow("clone", CV_WINDOW_AUTOSIZE);
imshow("clone", clone);
//复制图像:copyTo
Mat copy;
src.copyTo(copy);
namedWindow("copy", CV_WINDOW_AUTOSIZE);
imshow("copy", copy);
waitKey(0);
return 0;
}
输出图像的内存是自动分配的
使用OpenCV的C++接口,不需要考虑内存分配问题
赋值操作和拷贝构造函数只会复制头部分
使用clone与copyTo两个函数实现数据完全复制
2.行数、列数、通道数
int dst_cols = dst.cols;
int dst_rows = dst.rows;
int dst_channels = dst.channels();
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat src;
src = imread("D:/code/vproject/car-1.jpg");
if (src.empty()) {
cout << "could not load image..." << endl;
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
Mat dst;
namedWindow("output", CV_WINDOW_AUTOSIZE);
cvtColor(src, dst, CV_BGR2GRAY);
int dst_cols = dst.cols;
int dst_rows = dst.rows;
int dst_channels = dst.channels();
int src_channels = src.channels();
printf("dst行:%d\n", dst_rows);
printf("dst列:%d\n", dst_cols);
printf("dst变换为灰色后的图像的通道数:%d\n", dst_channels);
printf("src原图像的通道数:%d\n", src_channels);
imshow("output", dst);
waitKey(0);
return 0;
}
(3)Mat定义数组
1.创建 Mat M(3, 3, CV_8UC3, Scalar(0, 0, 255));
Mat M(3, 3, CV_8UC3, Scalar(0, 0, 255));
前两个参数分别表示行(row)跟列(column)、
第三个CV_8UC3中的8表示每个通道占8位
U表示无符号
C表示Char类型
3表示通道数目是3
第四个参数是向量表示初始化每个像素值是多少,向量长度对应通道数目一致
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat M(3, 3, CV_8UC3, Scalar(0, 0, 255));
// Mat M(30, 30, CV_8UC3, Scalar(0, 0, 255));
//把这个M打印出来:是一个3*3的红色矩阵
cout << "M=" << endl << M << endl;
namedWindow("M", CV_WINDOW_AUTOSIZE);
imshow("M", M);
waitKey(0);
return 0;
}
2.M.create
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat M;
M.create(4, 3, CV_8UC2);
M = Scalar(255, 127);
cout << "M=" << endl << M << endl << endl;
//输出该矩阵的第一行的值
uchar* firstRow = M.ptr<uchar>(0);
printf("%d\n", *firstRow);
getchar();
return 0;
}
3.定义小的数组
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat src = imread("D:/code/vproject/car-1.jpg");
Mat csrc;
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(src, csrc, src.depth(), kernel);
namedWindow("csrc", CV_WINDOW_AUTOSIZE);
imshow("csrc", csrc);
waitKey(0);
return 0;
}
6.第4节课:图像操作(读写修改像素)
(1)读写 && 修改像素
1.黑白反差图
0:B
1:G
2:R
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat src, gray_src;
src = imread("D:/code/vproject/car-1.jpg");
if (src.empty()) {
cout << "could not load image..." << endl;
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
//转换成单通道图像
cvtColor(src, gray_src, CV_BGR2GRAY);
namedWindow("output", CV_WINDOW_AUTOSIZE);
imshow("output", gray_src);
int height = gray_src.rows;
int width = gray_src.cols;
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int gray = gray_src.at<uchar>(row, col);
gray_src.at<uchar>(row, col) = 255 - gray;
}
}
//将形成的反差图输出
namedWindow("gray invert", CV_WINDOW_AUTOSIZE);
imshow("gray invert", gray_src);
waitKey(0);
return 0;
}
2.彩色反差图片
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat src, gray_src;
src = imread("D:/code/vproject/car-1.jpg");
if (src.empty()) {
cout << "could not load image..." << endl;
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
//形成彩色反差图片-手写
Mat dst;
dst.create(src.size(), src.type());
int height = src.rows;
int width = src.cols;
int nc = src.channels();
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
if (nc == 1) {
int gray = gray_src.at<uchar>(row, col);
gray_src.at<uchar>(row, col) = 255 - gray;
}
else if (nc == 3) {
int b = src.at<Vec3b>(row, col)[0];
int g = src.at<Vec3b>(row, col)[1];
int r = src.at<Vec3b>(row, col)[2];
dst.at<Vec3b>(row, col)[0] = 255 - b;
dst.at<Vec3b>(row, col)[1] = 255 - g;
dst.at<Vec3b>(row, col)[2] = 255 - r;
}
}
}
namedWindow("dst手写反差图片", CV_WINDOW_AUTOSIZE);
imshow("dst手写反差图片", dst);
//形成彩色反差图片-函数bitwise_not
Mat bitwise;
bitwise_not(src, bitwise);
namedWindow("bitwise_not反差图片", CV_WINDOW_AUTOSIZE);
imshow("bitwise_not反差图片", bitwise);
waitKey(0);
return 0;
}
3.Vec3b Vec3F
Vec3b对应三通道的顺序是blue、green、red的uchar类型数据。
Vec3f对应三通道的float类型数据
把CV_8UC1转换到CV32F1实现如下:
src.convertTo(dst, CV_32F);
7.第5节课:图像混合
(0)模板
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat src;
src = imread("D:/code/vproject/car-1.jpg");
if (src.empty()) {
cout << "cout not load image... " << endl;
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
waitKey(0);
return 0;
}
(1)理论-线性混合操作
其中 的取值范围为0~1之间
对两幅图像进行操作,最后是一个混合的图像
(2)相关API(AddWeighted)权重
参数1:输入图像Mat – src1
参数2:输入图像src1的alpha值
参数3:输入图像Mat – src2
参数4:输入图像src2的alpha值
参数5:gamma值(校验值,防止太暗,最后加上去)
参数6:输出混合图像
注意点:两张图像的大小和类型必须一致才可以
保障最后的值在0~255之间
addWeighted(src1, alpha, src2, (1 - alpha), 0.0, dst);
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat src1, src2, dst;
src1 = imread("D:/code/vproject/LinuxLogo.png");
src2 = imread("D:/code/vproject/win7Logo.png");
if (src1.empty()) {
cout << "cout not load image Linux Logo... " << endl;
return -1;
}
if (src2.empty()) {
cout << "cout not load image win7 Logo... " << endl;
return -1;
}
double alpha = 0.5;
if (src1.rows == src2.rows && src1.cols == src2.cols && src1.type() == src2.type()) {
addWeighted(src1, alpha, src2, (1 - alpha), 0.0, dst);
imshow("LinuxLogo", src1);
imshow("win7Logo", src2);
namedWindow("blend demo", CV_WINDOW_AUTOSIZE);
imshow("blend demo", dst);
}
else {
cout << "image size is not same" << endl;
return -1;
}
waitKey(0);
return 0;
}
(3)直接add两图片
add(src1, src2, dst, Mat());
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat src1, src2, dst;
src1 = imread("D:/code/vproject/LinuxLogo.png");
src2 = imread("D:/code/vproject/win7Logo.png");
if (src1.empty()) {
cout << "cout not load image Linux Logo... " << endl;
return -1;
}
if (src2.empty()) {
cout << "cout not load image win7 Logo... " << endl;
return -1;
}
double alpha = 0.5;
if (src1.rows == src2.rows && src1.cols == src2.cols && src1.type() == src2.type()) {
add(src1, src2, dst, Mat());
imshow("LinuxLogo", src1);
imshow("win7Logo", src2);
namedWindow("add demo", CV_WINDOW_AUTOSIZE);
imshow("add demo", dst);
}
else {
cout << "image size is not same" << endl;
return -1;
}
waitKey(0);
return 0;
}
(4)两图片相乘
multiply(src1, src2, dst, 1.0);
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat src1, src2, dst;
src1 = imread("D:/code/vproject/LinuxLogo.png");
src2 = imread("D:/code/vproject/win7Logo.png");
if (src1.empty()) {
cout << "cout not load image Linux Logo... " << endl;
return -1;
}
if (src2.empty()) {
cout << "cout not load image win7 Logo... " << endl;
return -1;
}
double alpha = 0.5;
if (src1.rows == src2.rows && src1.cols == src2.cols && src1.type() == src2.type()) {
multiply(src1, src2, dst, 1.0);
imshow("LinuxLogo", src1);
imshow("win7Logo", src2);
namedWindow("add demo", CV_WINDOW_AUTOSIZE);
imshow("add demo", dst);
}
else {
cout << "image size is not same" << endl;
return -1;
}
waitKey(0);
return 0;
}
8.第6节课:调整图像亮度与对比度
(1)理论
图像变换可以看作如下:
- 像素变换 – 点操作
- 邻域操作 – 区域
1.重要的API
Mat new_image = Mat::zeros( image.size(), image.type() ); 创建一张跟原图像大小和类型一致的空白图像、像素值初始化为0
saturate_cast<uchar>(value)确保值大小范围为0~255之间
Mat.at<Vec3b>(y,x)[index]=value 给每个像素点每个通道赋值
(2)代码
1.彩色图像
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat src, dst;
src = imread("D:/code/vproject/timg.jpg");
if (src.empty()) {
cout << "cout not load image... " << endl;
return -1;
}
char input_win[] = "input image";
namedWindow(input_win, CV_WINDOW_AUTOSIZE);
imshow(input_win, src);
int height = src.rows;
int width = src.cols;
dst = Mat::zeros(src.size(), src.type());
float alpha = 1.2;
float beta = 50;
Mat m1;
src.convertTo(m1, CV_32F);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
if (src.channels() == 3) {
float b = m1.at<Vec3f>(row, col)[0];// blue
float g = m1.at<Vec3f>(row, col)[1]; // green
float r = m1.at<Vec3f>(row, col)[2]; // red
dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b * alpha + beta);
dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g * alpha + beta);
dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r * alpha + beta);
}
else if (src.channels() == 1) {
float v = src.at<uchar>(row, col);
dst.at<uchar>(row, col) = saturate_cast<uchar>(v * alpha + beta);
}
}
}
char output_title[] = "contrast and brightness change demo";
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
imshow(output_title, dst);
waitKey(0);
return 0;
}
2.灰色图像
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat src, dst;
src = imread("D:/code/vproject/timg.jpg");
if (src.empty()) {
cout << "cout not load image... " << endl;
return -1;
}
char input_win[] = "input image";
cvtColor(src, src, CV_BGR2GRAY);
namedWindow(input_win, CV_WINDOW_AUTOSIZE);
imshow(input_win, src);
int height = src.rows;
int width = src.cols;
dst = Mat::zeros(src.size(), src.type());
float alpha = 1.2;
float beta = 50;
Mat m1;
src.convertTo(m1, CV_32F);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
if (src.channels() == 3) {
float b = m1.at<Vec3f>(row, col)[0];// blue
float g = m1.at<Vec3f>(row, col)[1]; // green
float r = m1.at<Vec3f>(row, col)[2]; // red
dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b * alpha + beta);
dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g * alpha + beta);
dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r * alpha + beta);
}
else if (src.channels() == 1) {
float v = src.at<uchar>(row, col);
dst.at<uchar>(row, col) = saturate_cast<uchar>(v * alpha + beta);
}
}
}
char output_title[] = "contrast and brightness change demo";
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
imshow(output_title, dst);
waitKey(0);
return 0;
}
9.第7节课