目录
六. add/subtract/divide/multiply
十七.rectangle(矩形)/circle(圆)/line(线)/ellipse(椭圆)
一.imread和imshow
读取图像 | imread |
显示图像 | imshow |
1.imread
Mat cv::imread(const String& filename, int flags = IMREAD_COLOR)
//imread函数读取出来都是Mat类型,所有的图片类型都是Matrix矩阵类型(二维数组)
//const String& filename:第一个参数是代表的完整的文件夹路径
//
标志参数 | 作用 |
IMREAD_COLOR或者1(默认) | imread按三通道方式读入图像,即彩色图像 |
IMREAD_GRAYSCALE或者0 | imread按单通道的方式读入图像,即灰度图像 |
IMREAD_UNCHANGED或者-1 | imread按解码得到的方式读入图像 |
2.imshow
void cvimshow(const cv:String &winname, cv::lnputArray mat)
//第一个参数:表示窗口的名称
//第二个参数:表示要输出的图像的数据对象
举例:
Mat img; //声明一个保存图像的类
img = imread("F:/picture/yang.png",1);//彩色图像
//img=imread("F:/picture/yang.png",0);灰度图像
imshow("test", img); //显示图像
二.waitKey和destoryAllWindows()
显示指定的图像(毫秒) | waitKey() |
销毁所有创建的窗口 | destoryAllWindows() |
1.waitKey()
waitKey()与waitKey(0),都代表无限等待一直阻塞,非常适合一直显示图像。
waitKey(n),显示n毫秒后,关闭显示的窗口。人眼可识别300毫秒以上的。
void Demo::Key_demo(Mat& img)
{
Mat dst = Mat::zeros(img.size(), img.type());
while (true)
{
int c = waitKey(100);//键盘响应
if (c == 27) { //ESc退出
break;
}
if (c == 49) { //按键1
std::cout << "you enter key #1" << std::endl;
cvtColor(img, dst, COLOR_BGR2GRAY);//将BGR->GRAY
}
if (c == 50) { //按键2
std::cout << "you enter key #2" << std::endl;
cvtColor(img, dst, COLOR_BGR2HSV); //将BGR->HSV
}
else if (c == 51) { //按键3
std::cout << "you enter key #3" << std::endl;
add(img, Scalar(100, 100, 100), dst); //图像增加亮度
}
imshow("图像转化后", dst);
}
}
2.destoryAllWindows()
destoryAllWindows(),将前面创建的所有窗口销毁了
三.namedWindow()
图像显示类型 | namedWindow() |
针对图像显示不全,使用函数namedWindow
namedWindow(winname, flags=None)
//第一个参数代表输入窗口的名称
//第二个参数代表输入窗口的类型
标志参数 | 作用 |
---|---|
WINDOW_NORMAL | 显示图像后,允许用户随意调整窗口大小 |
WINDOW_AUTOSIZE(默认类型) | 根据图像大小显示窗口,不允许用户调整大小 |
WINDOW_FREERATIO | 窗口大小自适应比例 |
WINDOW_KEEPRATIO | 保持图像的比例 |
举例:namedWindow("test", WINDOW_FREERATIO);
四.cvtColor和imwrite(色彩转化)
图像色彩空间转化 | cvtColor |
保存函数 | imwrite |
1.cvtColor
void cv::cvtColor(cv::InputArray src, cv::OutputArray dst,int code, int dstCn = 0
//第一个参数输入图像 Mat类型
//第二个参数输出图像 Mat类型
//第三个参数颜色映射类型
//第四个参数输出的通道数 (0='automatic'),我们可以使用默认值,什么都不写。
COLOR_BGR2GRAY=6 | 彩色到灰度 |
COLOR_GRAY2BGR=8 | 灰度到彩色 |
COLOR_BGR2HSV=40 | BGR到HSV |
COLOR_HSV2BGR=54 | HSV到BGR |
举例:
void Demo::cvtcolor_demo(Mat& img)
{
Mat gray, hsv;
cvtColor(img, gray, COLOR_BGR2GRAY);//bgr->gray
cvtColor(img, hsv, COLOR_BGR2HSV);//bgr->hsv
imshow("输出gray", gray);
imshow("输出hsv",hsv);
}
2.imwrite
bool cv::write(const String& filename, InputArray img,const std::vector<int>& params = std::vector<int>())
//第一个参数表示要保存在哪个目录下
//第二个参数表示要保存的图像 Mat类型
举例:
void Demo::cvtcolor_demo(Mat& img)
{
Mat gray, hsv;
cvtColor(img, gray, COLOR_BGR2GRAY);//bgr->gray
cvtColor(img, hsv, COLOR_BGR2HSV);
imshow("输出gray", gray);
imshow("输出hsv",hsv);
imwrite("F:/picture/jiajiagray.png", gray);//保存gray名字jiajiagray.png
imwrite("F:/picture/jiajiahsv.png", hsv);//保存hsv名字jiajiahsv.png
}
五.Mat/clone/copyto
image_in.copyTo(image_out);//把image_in这张图复制(copy to)到image_out上
image_in.copyTo(image_out,mask);
//把image_in这张图复制(copy to)到image_out上,且image_in对应mask中像素值为0的像素点都不会贴到image_out上
//创建方法 克隆
Mat m1=src.clone();
//复制
Mat m2;
src.copyTo(m2);
//赋值
Mat m3=src;
//创建空白图像
Mat m4=Mat::zeros(src.size(),src.type());//创建的大小与src相同,类型与src相同
Mat m5=Mat::zeros(Size(512,512),CV_8UC3);
Mat m6=Mat::ones(Size(512,512),CV_8UC3);
Mat m7(600,800,CV_8UC1);设置图像的高度是600,宽度是800,单通道
Mat m8(600,800,CV_8UC3);设置图像的高度是600,宽度是800,三通道
//c++11快速创建
Mat kernel=(Mat<char>(3,3)<<0,-1,0,
-1,5,-1,
0,-1,0)
1.创建与克隆
void Demo::mat_demo(Mat& img)
{
Mat m1, m2;
m1 = img.clone();
img.copyTo(m2);
}
2.打印一个8*8的单通道的8位的无符号的数据0
Mat m3 = Mat::zeros(Size(8, 8), CV_8UC1);
std::cout << "width:" << m3.cols << endl;
std::cout << "height:" << m3.rows << endl;
std::cout << "channels:" << m3.channels() << endl;
std::cout << m3 << endl;
3.打印一个8*8的三通道的8位的无符号的数据 0
Mat m3 = Mat::zeros(Size(8, 8), CV_8UC3);
std::cout << "width:" << m3.cols << endl;
std::cout << "height:" << m3.rows << endl;
std::cout << "channels:" << m3.channels() << endl;
std::cout << m3 << endl;
4.打印一个8*8的单通道的8位的无符号的数据 1
Mat m3 = Mat::ones(Size(8, 8), CV_8UC1);
std::cout << "width:" << m3.cols << endl;
std::cout << "height:" << m3.rows << endl;
std::cout << "channels:" << m3.channels() << endl;
std::cout << m3 << endl;
5.打印一个8*8的三通道的8位的无符号的数据 1
Mat m3 = Mat::ones(Size(8, 8), CV_8UC3);
std::cout << "width:" << m3.cols << endl;
std::cout << "height:" << m3.rows << endl;
std::cout << "channels:" << m3.channels() << endl;
std::cout << m3 << endl;
6.给三个通道赋值
错误的赋值
Mat m3 = Mat::zeros(Size(8, 8), CV_8UC3);
m3 = 127;//这样赋值只能给第一个像素点赋值
std::cout << "width:" << m3.cols << endl;
std::cout << "height:" << m3.rows << endl;
std::cout << "channels:" << m3.channels() << endl;
std::cout << m3 << endl;
正确的赋值
Mat m3 = Mat::zeros(Size(8, 8), CV_8UC3);
m3 = Scalar(127, 127, 127);
std::cout << "width:" << m3.cols << endl;
std::cout << "height:" << m3.rows << endl;
std::cout << "channels:" << m3.channels() << endl;
std::cout << m3 << endl;
7.展示颜色
Mat m3 = Mat::zeros(Size(200, 200), CV_8UC3);
m3 = Scalar(0, 0, 127);//Blue 0,Green 0,Red 127->红色
std::cout << "width:" << m3.cols << endl;
std::cout << "height:" << m3.rows << endl;
std::cout << "channels:" << m3.channels() << endl;
imshow("m3", m3);
六. add/subtract/divide/multiply
1.标量的加减乘除形式
void Demo::operator_demo(Mat& img)
{
Mat dst;
dst = img + Scalar(100, 100, 100);// 直接+标量实现
imshow("加操作", dst);
dst = img - Scalar(100, 100, 100);// 直接-标量实现
imshow("减操作", dst);
dst = img / Scalar(2, 2, 2);// 直接/标量实现
imshow("除操作", dst);
Mat m = Mat::zeros(img.size(), img.type());
m = Scalar(2, 2, 2);
multiply(img, m, dst);
imshow("乘操作", dst);
}
可以等价于 下面的
void Demo::operator_demo(Mat& img)
{
Mat dst = Mat::zeros(img.size(), img.type());//创建一个与img大小相同的黑幕布
Mat m = Mat::zeros(img.size(), img.type());//创建一个与img大小相同的黑幕布
m = Scalar(100, 100, 100);//m的标量大小
for (int row = 0; row < img.rows; row++)
{
for (int col = 0; col < img.cols; col++)
{
Vec3b p1 = img.at<Vec3b>(row, col);//提取每一个像素点
Vec3b p2 = m.at<Vec3b>(row, col);//提取每一个像素点
dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(p1[0] + p2[0]);//通道0处的相加
dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(p1[1] + p2[1]);//通道1处的相加
dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(p1[2] + p2[2]);//通道2处的相加
}
}
imshow("dst", dst);
}
saturate_cast<uchar>() 数据的转型,如果数据大于255则一直是255,如果数据小于0,就是0
2.直接操作API
加 | add |
减 | subtract |
乘 | divide |
除 | multiply |
Mat dst = Mat::zeros(image.size(), image.type());
Mat m = Mat::zeros(image.size(), image.type());
m = Scalar(50, 50, 50);
add(image, m, dst);//加法操作
imshow("加法操作", dst);
Mat dst = Mat::zeros(image.size(), image.type());
Mat m = Mat::zeros(image.size(), image.type());
m = Scalar(50, 50, 50);
subtract(image, m, dst);//减法操作
imshow("减法操作", dst);
Mat dst = Mat::zeros(image.size(), image.type());
Mat m = Mat::zeros(image.size(), image.type());
m = Scalar(2, 2, 2);
divide(image, m, dst);//除法操作
imshow("除法操作", dst);
Mat dst;
Mat m = Mat::zeros(image.size(), image.type());//创建一个图像大小与之前相同,类型相同
m = Scalar(2, 2, 2);
multiply(image, m, dst);//乘法操作
imshow("乘法操作", dst);
七.createTrackbar(滑动控件)
1.API介绍
快速创建一个滑动控件 | createTrackbar |
CV_EXPORTS int createTrackbar(const string& trackbarname,
const string& winname,
int* value,
int count,
TrackbarCallback onChange = 0,
void* userdata = 0);
//参数一、trackbarname:滑动空间的名称(滚动条的名字)
//参数二、winname:滑动空间用于依附的图像窗口的名称(滚动条用在什么窗口上)
//参数三、value:滑块位置一个初始值的,也就是告诉我们滑块最初位置在哪(以地址的形式)
//参数四、count:(滚动条的最大值)
//参数五、TrackbarCallback是回调函数(用来接收回调函数函数名),其定义如下:
//typedef void (CV_CDECL *TrackbarCallback)(int pos, void* userdata);
//int pos:它表示的是当前滑块所在的位置
//void* userdata:回调函数形参userdata的值就是通过createTrackbar()的形参userdata直接得到的
//参数六、用户传给回调函数的数据,用来处理轨迹条事件,默认值为0。(要强转成void*类型)
2.例子
//回调函数只调用一次解决滑块一开始的状态
static void on_track(int b, void* userdata)//回调函数(传值50,img传给回调函数)
{
Mat img = *((Mat*)userdata);
Mat dst = Mat::zeros(img.size(), img.type());
Mat m = Mat::zeros(img.size(), img.type());
m = Scalar(b, b, b);
add(img, m, dst);//开始的位置亮度是+50的
imshow("亮度调整", dst);
}
void Demo::tracking_demo(Mat& img)
{
namedWindow("亮度调整", WINDOW_AUTOSIZE);
int lightness = 50;//滑动窗口的最开始的值是50
createTrackbar("滚动条", "亮度调整", &lightness, 255, on_track, (void*)(&img));
on_track(50,&img);//创建回调函数(50表示的是当前滑块所在的位置,img传给回调函数)
}
static void on_track(int b, void* userdata)//回调函数(传值50,img传给回调函数)
{
Mat img = *((Mat*)userdata);
Mat dst = Mat::zeros(img.size(), img.type());
Mat m = Mat::zeros(img.size(), img.type());
m = Scalar(b, b, b);
subtract(img, m, dst);
imshow("亮度对比度调整", dst);
}
static void on_contrast(int b, void* userdata)//回调函数(传值50,img传给回调函数)
{
Mat img = *((Mat*)userdata);
Mat dst = Mat::zeros(img.size(), img.type());
Mat m = Mat::zeros(img.size(), img.type());
m = Scalar(b, b, b);
multiply(img,m,dst);
imshow("亮度对比度调整", dst);
}
void Demo::tracking_demo(Mat& img)
{
namedWindow("亮度对比度调整", WINDOW_AUTOSIZE);
int lightness = 100;
int contrast_value = 2;
createTrackbar("亮度调整", "亮度对比度调整", &lightness, 255, on_track, (void*)(&img));
createTrackbar("对比度调整", "亮度对比度调整", &contrast_value, 10, on_contrast, (void*)(&img));
on_track(100,&img);//创建回调函数(传值1用于加亮度,img传给回调函数)
on_contrast(2, &img);
}
八.addWeighted(图像比例混合)
1.API介绍
将两张相同大小,相同类型的图片融合的函数 | addWeighted |
void AddWeighted(const CvArr* src1,
double alpha,
const CvArr* src2,
double beta,
double gamma,
CvArr* dst
int dtype=-1));
//第一个参数 src1,第一个原数组 类型是Mat
//第二个参数 alpha,第一个数组元素权重(第一个数组占图形的比重)
//第三个参数 src2,第二个原数组 类型是Mat
//第四个参数 beta,第二个数组元素权重(第二个数组占图形的比重)
//第五个参数 gamma,图1与图2混合后添加的数值,总和等于255以上就是纯白色了,加到权重总和上的标量值
//第六个参数 dst,输出图片 类型是Mat
//第七个参数 dtype,int类型的dtype, 输出阵列的可选深度,默认值-1。当两个输入数组具有相同的深度时,这个参数设置为-1 (默认值)
// dst = src1[I] * alpha + src2[I] * beta + gamma
2.例子
static void on_lightness(int b, void* userdata)
{
Mat image = *((Mat*)userdata);
Mat dst = Mat::zeros(image.size(), image.type());
Mat m = Mat::zeros(image.size(), image.type());
addWeighted(image, 1.0, m, 0, b, dst);//比值权重image*1.0+m*0+b
imshow("亮度调整对比度调整", dst);
}
static void on_contrast(int b, void* userdata)
{
Mat image = *((Mat*)userdata);
Mat dst = Mat::zeros(image.size(), image.type());
Mat m = Mat::zeros(image.size(), image.type());
double contrast = b / 100.0;
addWeighted(image, contrast, m, 0.0, 0, dst);//比值权重image*b/100+m*0.0+b
imshow("亮度调整对比度调整", dst);
}
void Demo::tracking_demo(Mat& image)
{
namedWindow("亮度调整对比度调整", WINDOW_AUTOSIZE);
int lightness = 50;
int contrast_value = 100;
createTrackbar("Value Bar:", "亮度调整对比度调整", &lightness, 100, on_lightness, (void*)(&image));
createTrackbar("Contrast Bar:", "亮度调整对比度调整", &contrast_value, 200, on_contrast, (void*)(&image));
on_contrast(100, &image);//这个函数调用是来显示最初的图片的样子
on_lightness(100, &image);//这个函数调用是来显示最初的图片的样子
}
九.applyColorMap(伪色彩)
1.API介绍
伪色彩函数 | applyColorMap |
void applyColorMap(InputArray src, OutputArray dst, InputArray userColor)
//第一个参数 源图像(灰度图或彩色图(CV_8UC1 or CV_8UC3))
//第二个参数 在源图像上进行色彩映射后的结果图像
//第三个参数 提供的色彩图代码值
/* int colormap[] =
{
COLORMAP_AUTUMN,
COLORMAP_BONE,
COLORMAP_JET,
COLORMAP_WINTER,
COLORMAP_RAINBOW,
COLORMAP_OCEAN,
COLORMAP_SUMMER,
COLORMAP_SPRING,
COLORMAP_COOL,
COLORMAP_HSV,
COLORMAP_PINK,
COLORMAP_HOT,
COLORMAP_PARULA,
COLORMAP_MAGMA,
COLORMAP_INFERNO,
COLORMAP_PLASMA,
COLORMAP_VIRIDIS,
COLORMAP_CIVIDIS,
COLORMAP_TWILIGHT,
COLORMAP_TWILIGHT_SHIFTED,
};
*/
2.例子
void Demo::color_demo(Mat& img)
{
int colormap[] = {
COLORMAP_AUTUMN,
COLORMAP_BONE,
COLORMAP_JET,
COLORMAP_WINTER,
COLORMAP_RAINBOW,
COLORMAP_OCEAN,
COLORMAP_SUMMER,
COLORMAP_SPRING,
COLORMAP_COOL,
COLORMAP_HSV,
COLORMAP_PINK,
COLORMAP_HOT,
COLORMAP_PARULA,
COLORMAP_MAGMA,
COLORMAP_INFERNO,
COLORMAP_PLASMA,
COLORMAP_VIRIDIS,
COLORMAP_CIVIDIS,
COLORMAP_TWILIGHT,
COLORMAP_TWILIGHT_SHIFTED,
};
Mat dst = Mat::zeros(img.size(), img.type());
int index = 0;
while (true)
{
int c = waitKey(100);
if (c == 27) break;
else
{
//图片每过1s变一个颜色
applyColorMap(img, dst, colormap[index % 19]);
index++;
imshow("展示图片", dst);
waitKey(1000);
}
}
}
十.rectangle和Rect(创建矩形框)
1.API介绍
绘制矩形 | Rect |
绘制一个矩形框 | rectangle |
Rect(x,y,width,height);
//x, y 为左上角坐标, width, height 则为长和宽。
void rectangle(Mat& img,
Point pt1,
Point pt2,
const Scalar& color,
int thickness=1,
int lineType=8,
int shift=0)
//第一个参数 绘制的图像Mat类型
//第二个参数 矩形的一个顶点
//第三个参数 矩形对角线上的另一个顶点
//第四个参数 矩形的颜色
//第五个参数 组成矩形的线条的粗细程度。取负值时(如 CV_FILLED)函数绘制填充了色彩的矩形。
//第六个参数 线条的类型 (默认取8),有没有锯齿LINE_4()、LINE_8()、LINE_AA(反锯齿)
//第七个参数 坐标点的小数点位数
2.例子
Rect(100, 100, 80, 80)//等价于从Point(100,100)->point(180,180)的矩形
rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 0, 0), -1, 8, 0);//方式1
rectangle(m2, Point(20, 20), Point(100, 100), Scalar(0, 0, 255), -1, 8, 0);//方式2
Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);
Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);
rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 0, 0), -1, LINE_8, 0);
rectangle(m2, Point(120, 120), Point(200, 200), Scalar(0, 0, 255), -1, LINE_8, 0);
imshow("m1", m1);
imshow("m2", m2);
十一.逻辑运算符与或非
与 | bitwise_or | bitwise_or(m1, m2, dst) |
或 | bitewise_and | bitwise_and(m1,m2,dst) |
非 | bitewise_not | bitwise_not(image,dst) |
void Demo::bitwise_demo(Mat& img)
{
Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);
Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);
rectangle(m1, Rect(100, 100, 80, 80), Scalar(100, 100, 100), -1, LINE_8, 0);
rectangle(m2, Point(120, 120), Point(200, 200), Scalar(0, 0, 255), -1, LINE_8, 0);
imshow("m1", m1);
imshow("m2", m2);
Mat dst_or = Mat::zeros(img.size(), img.type());//创建幕布
Mat dst_and = Mat::zeros(img.size(), img.type());//创建幕布
Mat dst_not = Mat::zeros(img.size(), img.type());//创建幕布
bitwise_or(m1, m2, dst_or);//与
bitwise_and(m1, m2, dst_and);//或
bitwise_not(m1, dst_not);//非
imshow("or", dst_or);
imshow("and", dst_and);
imshow("not", dst_not);
}
十二.split和merge(图像通道分离)
一个图是基于红色通道,绿色通道,蓝色通道
通道分离 | split |
通道合并 | merge |
void Demo::channels_demo(Mat& img)
{
vector<Mat> mv;
split(img, mv);
imshow("blue", mv[0]);// mv[0]等效于mv.at(0)
imshow("green", mv[1]);
imshow("red", mv[2]);
}
void Demo::channels_demo(Mat& img)
{
vector<Mat> mv;
split(img, mv);
imshow("blue", mv[0]);
imshow("green", mv[1]);
imshow("red", mv[2]);
Mat dst;
mv[1] = 0;//消除掉绿色
mv[2] = 0;//消除掉红色
merge(mv, dst);//合并起来
imshow("蓝色", dst);
}
十三.mixChannels(图像通道混合)
//用法1
void cv::mixChannels (
InputArrayOfArrays src,
InputOutputArrayOfArrays dst,
const std::vector<int> & fromTo
)
//第一个参数 原图像类型Mat
//第二个参数 混合后的目标图像
//第三个参数 数组类型的fromTo
//int from_to[] = { 0,2,1,1,2,0 };//第0个通道跑到第2个通道里面去
//第1个通道跑到第1个通道里面去
//第2个通道跑到第0个通道里面去
//用法2
void cv::mixChannels
(
const Mat *src,//输入矩阵
size_t nsrcs,//输入矩阵的数量
Mat *dst, //输出矩阵
size_t ndsts, //输出矩阵的数量
const int *fromTo,//复制列表fromto
size_t npairs //复制列表的数量
)
//方法1
vector<int>from_to = {0,2,1,1,2,0};
//第0个通道跑到第2个通道里面去
//第1个通道跑到第1个通道里面去
//第2个通道跑到第0个通道里面去
mixChannels(img, dst, from_to);//从哪里到哪里,几对交换
//方法2
int from_to[] = {0,2,1,1,2,0};
//第0个通道跑到第2个通道里面去
//第1个通道跑到第1个通道里面去
//第2个通道跑到第0个通道里面去
mixChannels(&img, 1, &dst, 1,from_to,3);//从哪里到哪里,几对交换
Mat m(500, 500, CV_8UC3, Scalar(255, 255, 0));
Mat m2(500, 500, CV_8UC3);
vector<Mat> channels;
split(m, channels);
imshow("m", m); //原图m为青色
imshow("0", channels.at(0));//分离出蓝色通道的 255白色
imshow("1", channels.at(1));//分理处绿色通道的 255白色
imshow("2", channels.at(2));//分理处红色通道的 0黑色
vector<int> fromTo = {0,2,1,1,2,0}; //更改的通道
mixChannels(m,1 m2,1,fromTo);
vector<Mat> channels2;
split(m2, channels2);//分离通道
imshow("/m", m2);
imshow("/0", channels2.at(0));//分离蓝色通道的 0黑色
imshow("/1", channels2.at(1));//分离绿色通道的 255白色
imshow("/2", channels2.at(2));//分离红色通道的 255白色
waitKey(0);
十四. inRange(指定空间色彩提取)
inRange()函数可实现二值化功能,可以同时针对多通道进行操作,使用起来非常方便。主要是将在两个阈值内的像素值设置为白色(255),而不在阈值区间内的像素值设置为黑色(0)。
指定空间色彩提取 | inRange |
//该函数输出的dst是一幅二值化之后的图像
void inRange(InputArray src, //输入要处理的图像,可以为单通道或多通道。
InputArray lowerb,//包含下边界的数组或标量。
InputArray upperb, //包含上边界数组或标量。
OutputArray dst); //输出图像,与输入图像src 尺寸相同且为CV_8U 类型。
举例
void Demo::inrange_demo(Mat& img)
{
Mat hsv;
cvtColor(img, hsv, COLOR_BGR2HSV);//转换成HSV
Mat dst;
inRange(hsv, Scalar(0, 0, 221), Scalar(150, 30, 255), dst);//扣出颜色是白色
imshow("抠出白色的", dst);//其他颜色不保留,只保留白色,其他颜色用黑色保留
}
void Demo::inrange_demo(Mat& img)
{
Mat hsv;
cvtColor(img, hsv, COLOR_BGR2HSV);//转换成HSV
Mat dst;
inRange(hsv, Scalar(0, 0, 221), Scalar(150, 30, 255), dst);//扣出颜色是白色的
imshow("抠出白色的", dst);//其他颜色不保留
Mat redback = Mat::zeros(img.size(), img.type());
redback = Scalar(0, 0, 255);
bitwise_not(dst, dst);//将所有的颜色取反,白色变成黑色
imshow("取反", dst);
img.copyTo(redback, dst);
//将img拷贝到redback中,且image对应mask中像素值为0的像素点都不会贴到redback上。
imshow("成品", redback);
}
十五.minMaxLoc(计算最大最小值)
void minMaxLoc(InputArray src, //输入的数组,若是图像,需为单通道图像。
double* minVal, //返回最小值的指针。若无需返回,此值设为 NULL。
double* maxVal = 0, //返回最大值的指针。若无需返回,此值设为 NULL。
Point* minLoc = 0, //返回最小值位置的指针(二维情况下),无需返回,此值设为NULL。
Point* maxLoc = 0, //返回最大值位置的指针(二维情况下),无需返回,此值设为NULL。
InputArray mask = noArray());
//可选的掩膜操作,非零掩码元素用于标记待统计元素,需要与输入图像集有相同尺寸。
void Demo::static_demo(Mat& img)
{
double minv, maxv;
Point minLoc;//最小值地址 point点坐标类型
Point maxLoc;//最大值地址 point点坐标类型
vector<Mat> mv;
split(img, mv);//分离通道mv[0] mv[1] mv[2]从三通道变成单通道
for (int i = 0; i < mv.size(); i++)
{
minMaxLoc(mv[i], &minv, &maxv, &minLoc, &maxLoc, Mat());
cout << "No.channels:" << i
<< " min value:" << minv
<< "max value:" << maxv << std::endl;
}
}
十六.meanStdDev(计算均值和标准方差)
void meanStdDev(InputArray src, //src输入数组,由1-4个通道组成,能够把结果存储到Scalar里
OutputArray mean, //mean 输出参数,计算平均值
OutputArray stddev,//stddev 输出参数,计算出的标准差
InputArray mask=noArray());//mask可选参数,操作掩摸,用以标记求取哪些区域。
Mat mean, stddev;
meanStdDev(img, mean, stddev,Mat());//mean是均值,stddev是方差
std::cout << "mean:" << mean << std::endl;
std::cout << "stddev:" << stddev << std::endl;
十七.rectangle(矩形)/circle(圆)/line(线)/ellipse(椭圆)
1.坐标系
2.Rect
Rect(x,y,width,height);
//x, y 为左上角坐标, width, height 则为长和宽。
//等价于
Rect rect;//定义矩形 定义坐标是左上角
rect.x = 200;
rect.y = 200;
rect.width = 100;
rect.height = 100;
Rect(200,200,100,100);
3.rectangle
void rectangle(Mat& img,
Point pt1,
Point pt2,
const Scalar& color,
int thickness=1,
int lineType=8,
int shift=0)
//第一个参数 绘制的图像Mat类型
//第二个参数 矩形的一个顶点
//第三个参数 矩形对角线上的另一个顶点
//第四个参数 矩形的颜色
//第五个参数 组成矩形的线条的粗细程度。取负值时(如 CV_FILLED)函数绘制填充了色彩的矩形。
//第六个参数 线条的类型 (默认取8),有没有锯齿LINE_4()、LINE_8()、LINE_AA(反锯齿)
//第七个参数 坐标点的小数点位数
rectangle(bg, Rect(200, 200, 100, 100), Scalar(255, 0, 0), -1, LINE_8, 0);
Rect rect;
rect.x = 100;
rect.y = 100;
rect.width = 100;
rect.height = 100;
rectangle(bg, rect, Scalar(0, 255, 0), -1, LINE_8, 0);
4.circle
circle(cv::InputOutputArray img, //画圆的图像Mat类型
cv::Point center, //圆的圆心Point类型
int radius, //圆的半径
const cv::Scalar&color,//圆的颜色
int thickness=1, //如果为整数,表示圆轮廓的厚度;如果为负数,表示要绘制一个填充的圆
int lineType =8 //圆形边界的类型
int shift =0)//位移中心坐标和半径值的小数位数
circle(bg, Point(50, 50), 50, Scalar(0, 0, 255), -1, LINE_8, 0);
//圆心坐标(50,50),半径50,颜色红色,填充,边缘LINE_8,0
5.line
CV_EXPORTS_W void line(InputOutputArray img, //要绘制线段的图像
Point pt1, //线段的起点
Point pt2, //线段的终点
const Scalar& color, //颜色
int thickness = 1, //线条的宽度
int lineType = LINE_8, //线条类型
int shift = 0)//坐标点小数点位数
line(bg, Point(160, 60), Point(200, 60), Scalar(0, 0, 255), 2, LINE_AA, 0);
6.ellipse
void ellipse(cv::InputOutputArray img,
const cv.:RotatedRect &box, //RotatedRect类型
const cv.:Scalar &color,
int thickness = 1,
int lineType =img: lmage)
void cv::ellipse( InputOutputArray img, //要绘制的图像
Point center, //圆心
Size axes, //轴的长度
double angle, //偏转的角度
double startAngle,//圆弧起始角的角度
double endAngle, //圆弧终结角的角度
const Scalar & color, //颜色
int thickness = 1, //线宽
int lineType = LINE_8,//线的类型
int shift = 0 //小数位数
)
RotatedRect rrt;
rrt.center = Point(150, 150);//椭圆的圆心
rrt.size = Size(200, 200);//弧度的高低,x轴方向的长度,y轴方向的长度
rrt.angle = 0.0;
ellipse(bg, rrt, Scalar(255, 0, 0), 1,LINE_8);
ellipse(bg, Point(150, 150), Size(100, 50), 0.0, 0.0, 360.0, Scalar(255, 0, 0), 1, LINE_8, 0);
十八.polylines多边形图像绘制
void polylines(Mat& img, //在img表示的图像上绘制
const Point** pts, //是指向多边形数组的指针,必须是const修饰的
const int* npts, //是多边形顶点个数的数组名
int ncontours, //绘制多边形的个数
bool isClosed, //表示多边形是否闭合,1表示闭合,0表示不闭合
const Scalar& color, //颜色
int thickness=1,
int lineType=8,
int shift=0 );
void Demo::polyline_demo(Mat& img)
{
Mat canvas = Mat::zeros(Size(500, 500), CV_8UC3);
Point p1(50, 25);
Point p2(37, 75);
Point p3(75, 50);
Point p4(25, 50);
Point p5(63, 75);
Point p6(50, 25);
std::vector<Point> pts;
pts.push_back(p1);
pts.push_back(p2);
pts.push_back(p3);
pts.push_back(p4);
pts.push_back(p5);
pts.push_back(p6);
polylines(canvas, pts, true, Scalar(0, 255, 0), 1, LINE_8, 0);//依次链接的,不能填充
imshow("绘制图像", canvas);
}
//创建一个二维数组,每一行存储一个多边形的点,总共存储了两个多边形的点
Point p[2][5] =
{{Point(100, 100),Point(150, 50),Point(180, 90),Point(10, 190),Point(200, 267)},
{Point(360, 410), Point(700, 650), Point(334,456), Point(531, 463), Point(384, 634)}};
const Point *pp[] ={p[0], p[1]};//这个指针数组存储每一个多边形的定点所在的一维数组的地址
int n[] = {5, 5};//这个数组存储每一个多边形的定点个数
polylines(src, pp, n, 2, 1, Scalar(255, 255, 0), 1);//绘制两个不填充的多边形
十九.fillPoly多边形图像填充
void fillPoly(Mat& img, //在img表示的图像上绘制
const Point** pts, //是指向多边形数组的指针,必须是const修饰的
const int* npts, //是多边形顶点个数的数组名
int ncontours, //是绘制多边形的个数
const Scalar& color, //颜色
int lineType=8,
int shift=0,
Point offset=Point() );
void QuickDemo::polyline_drawing_demp(Mat& image)
{
Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);//绘制底图
Point p1(100, 100);//找多边形的五个点
Point p2(50, 125);
Point p3(75, 150);
Point p4(125, 150);
Point p5(150, 125);
std::vector<Point> pts;
pts.push_back(p1);
pts.push_back(p2);
pts.push_back(p3);
pts.push_back(p4);
pts.push_back(p5);
fillPoly(canvas, pts, Scalar(0, 0, 255), 8, 0);//填充
imshow("绘制图像", canvas);
}
二十.drawContours绘制与填充
void drawContours(InputOutputArray image, //image表示目标图像
InputArrayOfArrays contours, //输入的轮廓组,每一组轮廓由点vector构成,
int contourIdx, //指明画第几个轮廓,如果该参数为负值,则画全部轮廓
const Scalar& color, //color为轮廓的颜色
int thickness=1, //轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部
int lineType=8, //线型
InputArray hierarchy=noArray(), //轮廓结构信息
int maxLevel=INT_MAX,
Point offset=Point() )
Point p1(100, 100);
Point p2(50, 125);
Point p3(75, 150);
Point p4(125, 150);
Point p5(150, 125);
std::vector<Point> pts;
pts.push_back(p1);
pts.push_back(p2);
pts.push_back(p3);
pts.push_back(p4);
pts.push_back(p5);
vector<vector<Point>> contours;
contours.push_back(pts);//插入一个点集
//contours可以绘制无穷个多边形,里面存放每一个多边形的点集
drawContours(canvas, contours, -1, Scalar(0, 0, 255), -1);
//第一个0代表绘制vector第几个 0 ,1,2...如果是-1就是全绘制
imshow("绘制图像", canvas);
二十一.rng.uniform产生随机数
rng.uniform(1, 3); //在[1,3)区间,随机生成一个整数
void QuickDemo::random_drawing_demo(Mat& image)
{
Mat canvas = Mat::zeros(Size(512,512),CV_8UC3);//绘制底图
int w = canvas.cols;//宽度
int h = canvas.rows;//高度
RNG rng(12345);//构造方法设定一个具体值,表示下面代码每次生成的结果都是一样的
while (true) {
int c = waitKey(10);
if (c == 27) {
break;
}
int x1 = rng.uniform(0, w);//坐标点的范围
int y1 = rng.uniform(0, h);//坐标点的范围
int x2 = rng.uniform(0, w);//坐标点的范围
int y2 = rng.uniform(0, h);//坐标点的范围
int b = rng.uniform(0, 255);//0-255上的随机颜色
int g = rng.uniform(0, 255);//0-255上的随机颜色
int r = rng.uniform(0, 255);//0-255上的随机颜色
line(canvas, Point(x1, y1), Point(x2, y2), Scalar(b, g, r), 1, 8, 0);//产生线
imshow("绘制演示", canvas);
}
}
二十二.setMouseCallback(鼠标绘制)
void setMousecallback(const string& winname, //winname:窗口的名字
MouseCallback onMouse,
//onMouse:鼠标响应函数,回调函数。指定窗口里每次鼠标时间发生的时候,被调用的函数指针。
//这个函数的原型应该为:void on_Mouse(int event, int x, int y, int flags, void* param);
void* userdata=0)//userdate:传给回调函数的参数
void on_Mouse(int event, int x, int y, int flags, void* param);
event是 CV_EVENT_*变量之一
x和y是鼠标指针在图像坐标系的坐标(不是窗口坐标系)
flags是CV_EVENT_FLAG的组合, param是用户定义的传递到setMouseCallback函数调用的参数。
附常用的event:
EVENT_MOUSEMOVE //鼠标移动
EVENT_LBUTTONDOWN //左键按下
EVENT_RBUTTONDOWN //右键按下
EVENT_LBUTTONUP //左键松
EVENT_RBUTTONUP //右键松
Point sp(-1, -1);//初始位置
Point ep(-1, -1);//结束位置
Mat tmp;
static void on_draw(int event, int x, int y, int flags, void* param)
{
Mat img = *((Mat*)param);
if (event == EVENT_LBUTTONDOWN)//如果鼠标第一个事件(按下)
{
sp.x = x;
sp.y = y;
std::cout << "start point:" << sp << std::endl;//显示初始的位置
}
else if (event == EVENT_LBUTTONUP)//鼠标松开(结束的位置)
{
ep.x = x;
ep.y = y;
int dx = ep.x - sp.x;//开始到结束的x轴距离
int dy = ep.y - sp.y;//开始到结束的y轴距离
if (dx > 0 && dy > 0)
{
Rect rect(sp.x, sp.y, dx, dy);//绘制一个矩形框
rectangle(img, rect, Scalar(0, 0, 255), 1, 8, 0);
imshow("ROI区域", img(rect));//将图形小窗口展示
}
sp.x = -1;//回归(-1,-1)
sp.y = -1;//回归(-1,-1)
}
else if (event == EVENT_MOUSEMOVE)//显示鼠标移动(每次移动前都要去擦除前面哪个状态)
{
if (sp.x > 0 && sp.y > 0)//必须是大于0才能去绘制,否则就一直在绘制
{
ep.x = x;
ep.y = y;
int dx = ep.x - sp.x;//开始到结束的x轴距离
int dy = ep.y - sp.y;//开始到结束的y轴距离
if (dx > 0 && dy > 0)
{
tmp.copyTo(img);//绘制一个就要将前一个状态拷贝下来
Rect rect(sp.x, sp.y, dx, dy);//绘制一个矩形框
rectangle(img, rect, Scalar(0, 0, 255), 1, 8, 0);
imshow("鼠标绘制", img);
}
}
}
}
void Demo::mouse_demo(Mat& img)
{
namedWindow("鼠标绘制", WINDOW_AUTOSIZE);
setMouseCallback("鼠标绘制", on_draw, (void*)&img);
imshow("鼠标绘制", img);
tmp = img.clone();
}
二十二.convertTo(缩放并转换到另外一种数据类型)
src.convertTo(dst, type, scale, shift)
//第一个参数 目的矩阵
//第二个参数 需要的输出矩阵类型,或者更明确的,是输出矩阵的深度,如果是负值(常用-1)则输出矩阵和输入矩阵类型相同;
//第三个参数 比例因子
//第四个参数 将输入数组元素按比例缩放后添加的值
//CV_8UC3转为CV_32FC3
Mat dst;
img.convertTo(dst, CV_32F);//将img转化成32位的浮点型
cout << img.type() << endl;
cout << dst.type() << endl;
二十三.normalize归一化函数
NORM_L1 //L1归一化
//sum(numbers)=20.0
// 2.0 0.1 (2.0/20.0)
// 8.0 0.4 (8.0/20.0)
// 10.0 0.5 (10.0/20.0)
NORM_L2 //L2,单位向量为1
// Norm to unit vector: ||positiveData||=1.0
// 2.0 0.15
// 8.0 0.62
// 10.0 0.77
NORM_MINMAX //根据delta=max-min
//Norm to range [0.0;1.0] 根据2-10区间的位置
// 2.0 0.0 (2的位置是左边界)
// 8.0 0.75 (6.0/8.0)
// 10.0 1.0 (10的位置是右边界)
NORM_INF //根据最大值
// 2.0 0.2 (2.0/10)
// 8.0 0.8 (8.0/10)
// 10.0 1.0 (10.0/10)
void cv::normalize(InputArray src, //输入矩阵
InputOutputArray dst,//输出矩阵,与输入矩阵尺寸相同
double alpha = 1,
//norm_type为NORM_MINMAX,则alpha为最小值或最大值;如果norm_type为其他类型,则为归一化要乘的系数
double beta = 0,
//norm_type为NORM_MINMAX,则beta为最小值或最大值;如果norm_type为其他类型,beta被忽略,此处不会被用到,一般传入0
int norm_type = NORM_L2,
//归一化类型,常见的有NORM_L1,NORM_L2,NORM_INF,NORM_MINMAX
int dtype = -1,
//如果取负值时,dst与src同样的类型;否则,dst和src有同样的通道数,且此时图像深度为CV_MAT_DEPTH(dtype)
InputArray mask = noArray())//可选操作掩膜
void Demo::norm_demo(Mat& img)
{
Mat dst;
cout << img.type() << endl;
img.convertTo(img, CV_32F);//将img转化成32位的浮点型
cout << img.type() << endl;
normalize(img, dst, 1.0, 0, NORM_MINMAX);
cout << dst.type() << endl;
imshow("图像归一化", img);
}
二十四.resize放缩和插值
resize(InputArray src, //输入,原图像,即待改变大小的图像;
OutputArray dst, //输出,改变后的图像。
Size dsize, //输出图像的大小,Size类型
double fx=0, //width方向的缩放比例,为0就按照src.cols
double fy=0, //height方向的缩放比例,为0就按照src.rows来计算
int interpolation=INTER_LINEAR )//这个是指定插值的方式
//INTER_NEAREST 最邻近插值
//INTER_LINEAR 线性插值,如果最后一个参数你不指定,默认使用这种方法
//INTER_CUBIC 4x4像素邻域内的双立方插值
//INTER_LANCZOS4 8x8像素邻域内的Lanczos插值
void QuickDemo::resize_demo(Mat& image)
{
Mat zoomin, zoomout;
int h = image.rows;
int w = image.cols;
resize(image, zoomin, Size(w / 2, h / 2), 0, 0, INTER_LINEAR);//线性插值
imshow("zoomin", zoomin);
resize(image, zoomout, Size(w * 2, h * 2), 0, 0, INTER_LINEAR);
imshow("zoomout", zoomout);
}
二十五.flip图像的翻转
CV_EXPORTS_W void flip(InputArray src, OutputArray dst, int flipCode);
//第一个参数 原来的图像
//第二个参数 结果图像
//第三个参数 参数flipCode一个标志,决定怎么翻转矩阵; 0是围绕着x轴翻转,正值是围绕着y轴翻转,负值是围绕着两个轴一起翻转。
void QuickDemo::flip_demo(Mat& image)
{
Mat dst;
flip(image, dst, 0);//0是上下反转
flip(image, dst, 1);//1是左右翻转
flip(image, dst, -1);//-1是180°反转
imshow("反转图像", dst);
}
二十六.warpAffine旋转和平移
void warpAffine(InputArray src, //原来的图像
OutputArray dst, //得到的图像
InputArray M, //仿射变换
Size dsize, //大小
int flags=INTER_LINEAR, //插值的方式(默认线性插值)
int borderMode=BORDER_CONSTANT, //边缘处理
const Scalar& borderValue=Scalar())//底色
void QuickDemo::rotate_demo(Mat& image)
{
Mat dst, M;
int w = image.cols;
int h = image.rows;
M = getRotationMatrix2D(Point2f(w / 2, h / 2), 45, 1.0);
warpAffine(image, dst, M, image.size(),INTER_LINEAR,0,Scalar(255,0,0));
imshow("旋转演示", dst);
}
二十七.capture摄像头处理
方法cv::VideoCapture capture(const string& filename); // 从视频文件读取
例程cv::VideoCapture capture("C:/Users/DADA/DATA/gogo.avi"); // 从视频文件读取
void QuickDemo::Quick_video(Mat& image)
{
VideoCapture capture(0);//视频捕捉设备 id ---笔记本电脑的用0
Mat frame;
while (true)
{
capture.read(frame);
if (frame.empty())
{
break;
}
imshow("frame", frame);
int c = waitKey(10);
if (c == 27)
{
break;
}
}
}