通道分离和合并
void QuickDemo::channels_demo(Mat& image)
{
std::vector<Mat> vm;
split(image, vm);
//按照B、G、R次序提取出image对象里的元素值
imshow("蓝色", vm[0]);
imshow("绿色", vm[1]);
imshow("红色", vm[2]);
}
通过split函数将存储在image对象当中的三色提取出来,分别是[B、G、R]。
在合并的过程会发生有趣的现象,总结出了一些规律,如果一共是三个通道,而在合并的时候如果缺少某个通道,那么合并的结果就是该通道的颜色。
比如:
B + G == R
B + R == G
G + R == B
- 蓝色和绿色合并的结果就是红色
- 蓝色和红色合并的结果就是绿色
- 绿色和红色合并的结果就是蓝色
void QuickDemo::channels_demo(Mat& image)
{
std::vector<Mat> vm;
split(image, vm);
//合并
Mat dst;
vm[0] = 0; //B
vm[1] = 0; //G
merge(vm, dst);
imshow("合并之后", dst);
}
mixChannels 函数原型一
- 功能:主要是通过from_to[] 数组完成通道之间的拷贝
void cv::mixChannels (
InputArrayOfArrays src,
InputOutputArrayOfArrays dst,
const std::vector< int > & fromTo
)
参数介绍
- 第一个参数:输入矩阵
- 第二个参数:输出矩阵
- 第三个参数:复制列表,表示第输入矩阵的第几个通道复制到输出矩阵的第几个通道
比如 {0,2,1,1,2,0}表示:
- src颜色通道0复制到dst颜色通道2
- src颜色通道1复制到dst颜色通道1
- src颜色通道2复制到dst颜色通道0
mixChannels 函数原型二
void cv::mixChannels
(
const Mat * src,
size_t nsrcs,
Mat * dst,
size_t ndsts,
const int * fromTo,
size_t npairs
)
第一个参数:输入矩阵
第二个参数:输入矩阵的数量
第三个参数:输出矩阵
第四个参数:输出矩阵的数量
第五个参数:复制列表
第六个参数:复制列表的数量
在这个函数原型中,如果输入矩阵和输出矩阵都写1,那么就跟第一种函数原型是一致的了。
如果不为1,就可以实现多个矩阵组合并或者一个矩阵拆分为多个复杂矩阵等功能。
通道混合
void QuickDemo::channels_demo(Mat& image)
{
Mat dst = Mat::zeros(image.size(), image.type());
int from_to[] = {0,2, 1,1,2,0};
/*
0通道赋值到2通道
1通道赋值到1通道
2通道赋值到0通道
*/
mixChannels(&image,1, &dst,1, from_to, 3);
imshow("交换的图像", dst);
}
图像色彩空间转换
-
HSV 也称六角锥体模型(Hexcone Model)。、这个模型中颜色的参数分别是:色调(H),饱和度(S),亮度(V)。
-
色调H:用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,品红为300°;
-
饱和度S:取值范围为0.0~1.0;
-
亮度V:取值范围为0.0(黑色)~1.0(白色)。
HSV的模糊取值范围
H: 0— 180
S: 0— 255
V: 0— 255
此处把部分红色归为紫色范围:
提取mask对象
//提取mask值
void QuickDemo::inrange_demo(Mat& image)
{
Mat hsv;
//转换为hsv色彩的图像空间
cvtColor(image, hsv, COLOR_BGR2HSV);
Mat mask;
inRange(hsv, Scalar(35, 43, 46), Scalar(77, 255, 255), mask);
imshow("轮廓显示", mask);
}
将mask对象的像素点的值取反,再以只拷贝mask的方式拷贝至另一张图像上。
//提取mask值
void QuickDemo::inrange_demo(Mat& image)
{
Mat hsv;
cvtColor(image, hsv, COLOR_BGR2HSV);
imshow("人物", image);
Mat mask;
inRange(hsv, Scalar(100, 43, 46), Scalar(124, 255, 255), mask);
//imshow("轮廓", mask);
Mat obj = Mat::zeros(image.size(), image.type());
obj = Scalar(0, 43 , 46);
//由于copyTo方法只能拷贝白色的像素点,所以需要对原图像的mask
//进行一个取反操作, 这样就能将取反后的mask放到obj上
bitwise_not(mask, mask);
image.copyTo(obj, mask);
imshow("转移", obj);
}
首先需要先提取出mask,mask是属于这张图片除了背景以外的阴影部分。
Mat mask;
inRange(hsv, Scalar(100, 43, 46), Scalar(124, 255, 255), mask);
imshow("轮廓", mask);
通过提取出人物的整个轮廓,再将该轮廓上的所有细节拷贝到另外一个Mat对象上。
像素值统计
- meanStdDev: 求方差和均值。
- minMaxLoc:求像素点的最大值最小值和坐标。
void QuickDemo::pixel_statistic_demo(Mat& image)
{
double minv;
double maxv;
Point minLoc;
Point maxLoc;
std::vector<Mat> mv;
split(image, mv);
for (int i = 0; i < mv.size(); i++) {
minMaxLoc(mv[i], &minv, &maxv, &minLoc, &maxLoc, Mat());
std::cout << "第" << i << "统计 " << "min value: " << minv << "max value: " << maxv << std::endl;
}
//求出均值跟方差
Mat stddev, mean;
meanStdDev(image ,mean, stddev);
std::cout << "均值:";
for (int i = 0; i < 3; i++) {
std::cout << " " << mean.at<double>(i);
}
std::cout << std::endl;
std::cout << "方差:";
for (int i = 0; i < 3; i++) {
std::cout << " " << stddev.at<double>(i);
}
std::cout << std::endl;
}
图像几何绘制
void QuickDemo::draw_demo(Mat& image)
{
//设置背景
Mat m = Mat::zeros(image.size(), image.type());
m = Scalar(0,0,0);
//在m图像上绘制红色矩形
// 矩形原点以及宽高 颜色 填充
rectangle(m,Rect(120, 120, 200, 200), Scalar(0, 0, 255), -1, LINE_8, 0);
//在m图像上绘制蓝色圆形
// 原点 半径 圆颜色 填充
circle(m, Point(325, 325), 10, Scalar(255, 0, 0), -1, LINE_8, 0);
//在m图像绘制绿色线条
// 线段原点 线段结尾位置 线段颜色 绘制
line(m, Point(120, 120), Point(320, 320), Scalar(0, 255, 0), 2, LINE_8, 0);
//绘制椭圆
RotatedRect rrt;
rrt.center = Point(120, 120); //原点
rrt.size = Size(100, 200); //大小
rrt.angle = 240.0; //以Point为旋转角度
//在m对象上绘制rrt规则的椭圆
ellipse(m, rrt, Scalar(150, 22,30));
imshow("绘制几何", m);
}
随机数与随机颜色
在OpenCV中,有个RNG类,用它来产生随机数。可以使用RNG的构造函数,来创建随机数生成器的对象。代码如下:
RNG rng(12345); //指定随机种子位12345
uniform()
-
关于RNG类,再提到一个它的函数,uinform()
-
uniform:指定了一个在a和b范围的均匀分布的随机数
rng.uniform(1,255); //返回一个在1~255范围内的随机数
随机绘制直线并填充色彩
void QuickDemo::rangdrawing_demo()
{
Mat m = Mat::zeros(Size(512, 512), CV_8UC3);
int w = m.rows;
int h = m.cols;
m = Scalar(0, 0 ,0);
RNG rng(12345); //随机种子
while (true) {
int val = waitKey(200);
if (val == 27) {
break;
}
//随机点与随机色的设置
int pointx = rng.uniform(0, w);
int pointy = rng.uniform(0, h);
int linew = rng.uniform(0, w);
int lineh = rng.uniform(0, h);
int b = rng.uniform(0, 255);
int g = rng.uniform(0, 255);
int r = rng.uniform(0, 255);
//绘制线段
line(m, Point(pointx, pointy), Point(linew, lineh), Scalar(b, g, r), 1);
imshow("随机绘制", m);
}
}
多边形填充与绘制
- 绘制: polylines(m, ptv, true, Scalar(0, 0 ,255),1, 8, 0);
- 填充 fillPoly(m, ptv,Scalar(0, 0, 255),8, 0);
void QuickDemo::drwaing_polygon_demo()
{
Mat m = Mat::zeros(Size(512, 512), CV_8UC3);
m = Scalar(0, 0, 0);
std::vector<Point> ptv;
int x, y;
int n = 0;
std::cout << "输入几变形";
std::cin >> n;
for (int i = 0; i < n; i++) {
std::cin >> x;
std::cin >> y;
ptv.push_back(Point(x, y));
}
//绘制多边
polylines(m, ptv, true, Scalar(0, 0 ,255),1, 8, 0);
imshow("绘制多边形", m);
//多边形填充
fillPoly(m, ptv,Scalar(0, 0, 255),8, 0);
imshow("填充多边形", m);
}
效果:
- drawContours函数 : 优点是绘制 + 填充一个或多个多边形
void drawContours(InputOutputArray image, InputArrayOfArrays contours,
int contourIdx, const Scalar& color, int thickness=1, int lineType=8,
InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )
- 其中第一个参数image表示目标图像,
- 第二个参数contours表示输入的轮廓组,每一组轮廓由点vector构成,
- 第三个参数contourIdx指明画第几个轮廓,如果该参数为负值,则画全部轮廓,
- 第四个参数color为轮廓的颜色,
- 第五个参数thickness为轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部,
- 第六个参数lineType为线型,
- 第七个参数为轮廓结构信息,
- 第八个参数为maxLevel
void QuickDemo::drwaing_polygon_demo()
{
Mat m = Mat::zeros(Size(512, 512), CV_8UC3);
m = Scalar(0, 0, 0);
std::vector<Point> ptv;
int x, y;
int n = 0;
std::cout << "输入几变形";
std::cin >> n;
for (int i = 0; i < n; i++) {
std::cin >> x;
std::cin >> y;
ptv.push_back(Point(x, y));
}
std::vector<std::vector<Point>> pvv;
pvv.push_back(ptv);
drawContours(m, pvv, -1, Scalar(0, 0, 255), 2);
imshow("填充多边形", m);
}