一、颜色通道
1.通道分离:split()
原型
void split(
InputArray m,
OutputArrayOfArrays mv;
)
参数
- m:要进行分离的图像
- mv:输出的通道容器。一般是
vector<Mat>
容器
例子:分离三通道
Mat srcIamge=imread();
vector<Mat> channels;
split(srcImage,channels);
//使用at()来得到BGR的
Mat dstImageBlue=channels.at(0);
Mat dstImageGreen=channels.at(1);
Mat dstImageRed=channels.at(2);
2.通道合并merge()
原型
void merge(
InputArrayOfArrays mv;
OutputArray dst
)
参数
- mv:输入的通道容器。一般是
vector<Mat>
容器 - dst:合成的图像
例子:分离三通道
Mat dstImage;
merge(channels,dstImage);
二、效果
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
String windowNames[]={"Blue","Green","Red"};
String trackbarNames[]={"ThresholdbarBlue","ThresholdbarGreen","ThresholdbarRed"};
Mat g_srcImage;
Mat g_dstImageBlue;
Mat g_dstImageGreen;
Mat g_dstImageRed;
Mat g_dstImageBlueThreshold;
Mat g_dstImageGreenThreshold;
Mat g_dstImageRedThreshold;
int g_dstImageBlueThresholdValue=0;
int g_dstImageGreenThresholdValue=0;
int g_dstImageRedThresholdValue=0;
const int g_dstImageThresholdValueMax=255;
vector<Mat> g_channels;
void mySplit()
{
split(g_srcImage,g_channels);
g_dstImageBlue=g_channels.at(0);
g_dstImageGreen=g_channels.at(1);
g_dstImageRed=g_channels.at(2);
}
void onChange(int,void*)
{
//deep copy
g_dstImageBlue.copyTo(g_dstImageBlueThreshold);
g_dstImageGreen.copyTo(g_dstImageGreenThreshold);
g_dstImageRed.copyTo(g_dstImageRedThreshold);
//Threshold
g_dstImageBlueThreshold=g_dstImageBlueThreshold>g_dstImageBlueThresholdValue;
g_dstImageGreenThreshold=g_dstImageGreenThreshold>g_dstImageGreenThresholdValue;
g_dstImageRedThreshold=g_dstImageRedThreshold>g_dstImageRedThresholdValue;
//show
imshow(windowNames[0],g_dstImageBlueThreshold);
imshow(windowNames[1],g_dstImageGreenThreshold);
imshow(windowNames[2],g_dstImageRedThreshold);
}
int main()
{
g_srcImage=imread("M.jpg");
GaussianBlur(g_srcImage,g_srcImage,Size(61,61),0.0);
//split channels
mySplit();
//Window
namedWindow(windowNames[0],WINDOW_NORMAL);
namedWindow(windowNames[1],WINDOW_NORMAL);
namedWindow(windowNames[2],WINDOW_NORMAL);
//createTrackbar
createTrackbar(trackbarNames[0],windowNames[0],&g_dstImageBlueThresholdValue,g_dstImageThresholdValueMax,onChange);
createTrackbar(trackbarNames[1],windowNames[1],&g_dstImageGreenThresholdValue,g_dstImageThresholdValueMax,onChange);
createTrackbar(trackbarNames[2],windowNames[2],&g_dstImageRedThresholdValue,g_dstImageThresholdValueMax,onChange);
onChange(0,0);
waitKey();
return 0;
}
三、访问像素
1.单位
这个单位T
就是Mat的通道深度类型:OpenCV3之Mat类的类型type和深度depth
- 对应一个通道,用于单通道图像:T,比如
CV_8UC1
的uchar
- 对应n个通道,用于n通道图像:
Vec< T,n >
,比如Vec3b
。OpenCV的常用类:Scalar、Vec、Point、Size、Rect、RotatedRect、Ptr
2.方法
因为图像是以左上角为原点,所以x对应j(列),y对应i(行)。
(1)at动态地址计算
①i单下标
把每行拼接成一行算。
Mat A = (Mat_<uchar>(2,2)<<0,1,2,3);
cout << A << endl;
/**
[ 0, 1;
2, 3]
*/
// 第0个
printf("%d\n",A.at<uchar>(0));
// 0
// 第3个
printf("%d\n",A.at<uchar>(3));
// 3
②i、j行列双下标
格式:
- 单通道:
image.at<T>(i,j)
- 多通道:
image.at<Vec<T,n> >(i,j)[channel]
,比如image.at<Vec3b>(0,0)[0]
三通道图像左上角第0通道
这个[]
不是什么特殊的意思,这个就是Vec
向量的数组下标访问。
遍历方式像遍历数组一样,是从上往下遍历每一行,对应image.at<Vec3b>(i,j)
。但需要注意的at(i,j)对应图像的at(y,x),
如:读取一副彩色图像,选择红光的区域。将其区域的分离出来,做成一张二值图
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat srcImage=imread("S1.jpg");
//dstImage必须创建,要不然无法访问。
//这里的CV_8UC1表示单通道图
Mat dstImage=Mat::zeros(srcImage.size(),CV_8UC1);
//遍历方式是从上往下遍历每一行
for(int i=0;i<dstImage.rows;i++)
{
for(int j=0;j<dstImage.cols;j++)
{
//srcImage是三通道图,所以用Vec3b
//选择红光:R>200,G<150,B<150
if(srcImage.at<Vec3b>(i,j)[0]<150 && srcImage.at<Vec3b>(i,j)[1]<150 && srcImage.at<Vec3b>(i,j)[2]>200)
{
//dstImage是单通道图,所以用uchar
dstImage.at<uchar>(i,j)=255;
}
}
}
namedWindow("BGR",WINDOW_NORMAL);
imshow("BGR",dstImage);
waitKey();
return 0;
}
(2)迭代器
格式:
//定义
Mat_<T>::iterator begin=image.begin<T>()
Mat_<T>::iterator end=image.end<T>()
//使用
(*it)[channel]
如:
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat srcImage=imread("S1.jpg");
//dstImage必须创建,要不然无法访问。
//这里的CV_8UC1表示单通道图
Mat dstImage=Mat::zeros(srcImage.size(),CV_8UC1);
Mat_<Vec3b>::iterator it=srcImage.begin<Vec3b>();
Mat_<Vec3b>::iterator itend=srcImage.end<Vec3b>();
Mat_<uchar>::iterator dst=dstImage.begin<uchar>();
//遍历方式是从上往下遍历每一行
for(;it<itend;it++,dst++)
{
//srcImage是三通道图,所以用Vec3b
//选择红光:R>200,G<150,B<150
if((*it)[0]<150 && (*it)[1]<150 && (*it)[2]>200)
{
//dstImage是单通道图,所以用uchar
(*dst)=255;
}
}
namedWindow("dst",WINDOW_NORMAL);
imshow("dst",dstImage);
waitKey();
return 0;
}
(3)指针
格式:
T* data=image.ptr<T>(i); //行循环中:获取第i行的首地址
data[j]; //每行中的列循环中:获取像素的地址
如:
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat srcImage=imread("S1.jpg");
//dstImage必须创建,要不然无法访问。
//这里的CV_8UC1表示单通道图
Mat dstImage=Mat::zeros(srcImage.size(),CV_8UC1);
//遍历方式是从上往下遍历每一行
for(int i=0;i<srcImage.rows;i++)
{
//srcImage是三通道图,所以用Vec3b
Vec3b* src=srcImage.ptr<Vec3b>(i);
//dstImage是单通道图,所以用uchar
uchar* dst=dstImage.ptr<uchar>(i);
for(int j=0;j<dstImage.cols;j++)
{
//srcImage是三通道图,所以用Vec3b
//选择红光:R>200,G<150,B<150
if(src[j][0]<150 && src[j][1]<150 && src[j][2]>200)
{
dst[j]=255;
}
}
}
namedWindow("dst",WINDOW_NORMAL);
imshow("dst",dstImage);
waitKey();
return 0;
}