一、Mat
Mat是OpenCV里最基本的一个类,用来表示图像。
// 默认构造函数 Mat A;
Mat ()
// 常用构造函数 Mat A(10,10,8UC3);
Mat (int rows, int cols, int type)
//Mat A(300, 400, CV_8UC3,Scalar(255,255,255));
Mat (int ndims, const int *sizes, int type, const Scalar &s)
Mat (Size size, int type)
Mat (int rows, int cols, int type, const Scalar &s)
Mat (Size size, int type, const Scalar &s)
Mat (int ndims, const int *sizes, int type)
Mat (const Mat &m)
Mat (int rows, int cols, int type, void *data, size_t step=AUTO_STEP)
Mat (Size size, int type, void *data, size_t step=AUTO_STEP)
Mat (int ndims, const int *sizes, int type, void *data, const size_t *steps=0)
Mat (const Mat &m, const Range &rowRange, const Range &colRange=Range::all())
//Mat D (A, Rect(10, 10, 100, 100) );
Mat (const Mat &m, const Rect &roi)
Mat (const Mat &m, const Range *ranges)
可以参考以下博文:
https://blog.csdn.net/u010248552/article/details/79962132
二、访问像素方式
1)指针方式
坐标的指针:
void colorReduce(const Mat& image,Mat& outImage,int div)
{
int nr=image.rows;
int nc=image.cols;
outImage.create(image.size(),image.type());
if(image.isContinuous()&&outImage.isContinuous())
{
nr=1;
nc=nc*image.rows*image.channels();
}
for(int i=0;i<nr;i++)
{ //行指针
const uchar* inData=image.ptr<uchar>(i);
uchar* outData=outImage.ptr<uchar>(i);
for(int j=0;j<nc;j++)
{ //列指针
*outData++=*inData++/div*div+div/2;
}
}
}
数据的指针:
//三通道
uchar *data = image.data ;
for(int h = 0 ; h < image.rows ; ++ h)
{
for(int w = 0 ; w < image.cols/2 ; ++ w)
{
*data ++ = 128 ;
*data ++ = 128 ;
*data ++ = 128 ;
}
}
imshow("data" , image) ;
//单通道
image = imread("forest.jpg" , 0) ;
imshow("image" , image) ;
data = image.data ;
for(int h = 0 ; h < image.rows ; ++ h)
{
for(int w = 0 ; w < image.cols/2 ; ++ w)
{
*data ++ = 128 ;
}
}
2)at方式
at方式相当于直接访问像素坐标:
void colorReduce(Mat& image,int div)
{
for(int i=0;i<image.rows;i++)
{
for(int j=0;j<image.cols;j++)
{
image.at<Vec3b>(i,j)[0]=image.at<Vec3b>(i,j)[0]/div*div+div/2;
image.at<Vec3b>(i,j)[1]=image.at<Vec3b>(i,j)[1]/div*div+div/2;
image.at<Vec3b>(i,j)[2]=image.at<Vec3b>(i,j)[2]/div*div+div/2;
}
}
}
3)迭代器访问
迭代器就是通过获得图像矩阵的开始和结束,然后增加迭代直至从开始到结束:
cv::Mat tempImage = srcImage.clone();
// 初始化源图像迭代器
cv::MatConstIterator_<cv::Vec3b> srcIterStart = srcImage.begin<cv::Vec3b>();
cv::MatConstIterator_<cv::Vec3b> srcIterEnd = srcImage.end<cv::Vec3b>();
// 初始化输出图像迭代器
cv::MatIterator_<cv::Vec3b> resIterStart = tempImage.begin<cv::Vec3b>();
cv::MatIterator_<cv::Vec3b> resIterEnd = tempImage.end<cv::Vec3b>();
// 遍历图像反色处理
while( srcIterStart != srcIterEnd )
{
(*resIterStart)[0] = 255 - (*srcIterStart)[0];
(*resIterStart)[1] = 255 - (*srcIterStart)[1];
(*resIterStart)[2] = 255 - (*srcIterStart)[2];
// 迭代器递增
srcIterStart++;
resIterStart++;
}
4)查找表函数
可以根据查找表的映射来进行像素的变换:
cv::Mat inverseColor6(cv::Mat srcImage)
{
int row = srcImage.rows;
int col = srcImage.cols;
cv::Mat tempImage = srcImage.clone();
// 建立LUT 反色table
uchar LutTable[256];
for (int i = 0; i < 256; ++i)
LutTable[i] = 255 - i;
cv::Mat lookUpTable(1, 256, CV_8U);
uchar* pData = lookUpTable.data;
// 建立映射表
for( int i = 0; i < 256; ++i)
pData[i] = LutTable[i];
// 应用索引表进行查找
cv::LUT(srcImage, lookUpTable, tempImage);
return tempImage;
}
可以参考以下博文:
https://blog.csdn.net/qq_20823641/article/details/51920846
三、感兴趣区域(ROI)
ROI允许我们选取图像特定的区域进行操作,有两种方式。
1)使用矩形(Rect)类
Mat ROI;
ROI=image(Rect_ (_Tp _x, _Tp _y, _Tp _width, _Tp _height));
x,y这两个参数就是矩形区域左上角的坐标
width,height这两个参数就是矩形局域的宽和高
2)手动指定感兴趣的行和列的范围
Mat ROI;
ROI=image(Rect_ (range(row_start,row_end),range(col_strat,col_end)));
range(row_start,row_end):行的开始和结束
range(col_strat,col_end):列的开始和结束
可以参考以下博文:
https://blog.csdn.net/xierhacker/article/details/52493746
四、绘制直方图
计算直方图:
void calcHist(const Mat* arrays, intnarrays, const int* channels, InputArray mask, OutputArray
hist, int dims,const int* histSize, const float** ranges, bool uniform=true, boolaccumulate=false );
参数解释:
- arrays:输入的图像的指针,可以是多幅图像,所有的图像必须有同样的深度,一副图像可以有多个channes。
- narrays:输入的图像的个数。
channels:用来计算直方图的channes的数组。比如输入是2副图像,第一副图像有0,1,2共三个channel,第二幅图像只有0一个channel,那么输入就一共有4个channes,如果int
channels[3] = {3, 2, 0},那么就表示是使用第二副图像的第一个通道和第一副图像的第2和第0个通道来计算直方图。
- mask:掩码。如果mask不为空,那么它必须是一个8位(CV_8U)的数组,并且它的大小的和arrays[i]的大小相同,值为1的点将用来计算直方图。
- hist:计算出来的直方图。
- dims:计算出来的直方图的维数。
- histSize:在每一维上直方图的个数。简单把直方图看作一个一个的竖条的话,就是每一维上竖条的个数。
- ranges:用来进行统计的范围。比如 float rang1[] = {0, 20};float rang2[] = {30, 40}; const float*rangs[] = {rang1, rang2};那么就是对0,20和30,40范围的值进行统计。
- uniform:每一个竖条的宽度是否相等。
- accumulate: 是否累加。如果为true,在下次计算的时候不会首先清空hist。
画出直方图:
void line(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness=1,
int lineType=8, int shift=0)
//两点确认一条直线。
//lineType:直线类型
//shift:坐标小数点维数
//画一个单一的实矩形
void rectangle(Mat& img, Point pt1,Point pt2, const Scalar& color, int thickness=1,
int lineType=8, int shift=0)
//一条对角线的两个顶点可确定一个矩形
//pt1和pt2互为对顶点
//thickness为负值表示矩形为实矩形
其中Point(x,y)表示二维坐标系下的点。
五、通道分离与合并通道
split用于通道分离
void split(const Mat& src,Mat *mvBegin)
第一个参数为要进行分离的图像矩阵,第二个参数是一个vector<Mat>对象
merge用于通道合并
void merge(const vector& mv, OutputArray dst );
第一个参数是图像矩阵向量容器,第二个参数是输出
举例:
std::vector<Mat> rgb(3);
split(src, rgb); //分离通道
for (int i = 0; i < 3; i++){
rgb[i] = rgb[i].mul(show);
}
merge(rgb, output); //合并通道
六、寻找矩阵最小最大值
void minMaxLoc(InputArray src, double* minVal, double* maxVal=0, Point* minLoc=0, Point* maxLoc=0, InputArray mask=noArray())
函数说明:
src:输入图像。
minVal:最小值,可輸入NULL表示不需要。
maxVal :最大值,可輸入NULL表示不需要。
minLoc:最小值的位置,可输入NULL表示不需要,Point类型。
maxLoc:最大值的位置,可输入NULL表示不需要,Point类型。
mask:可有可无的掩模。
七、绘制矩形
void rectangle(Mat& img, Point pt1,Point pt2,const Scalar& color, int thickness=1, int lineType=8, int shift=0)
img:输入图像.
pt1:矩形的一个顶点。
pt2:矩形对角线上的另一个顶点
color:线条颜色 (RGB) 或亮度(灰度图像 )(grayscale image)。
thickness:组成矩形的线条的粗细程度。取负值时(如 CV_FILLED)函数绘制填充了色彩的矩形。
line_type:线条的类型。
shift:坐标点的小数点位数。