0:必用头文件
#include <cxcore.h>
#include <cv.h>
#include <highgui.h>
#define WINDOW_AUTOSIZE 1
//CV_WINDOW_AUTOSIZE 这个宏是存在的
using namespace cv;
1:读取图片,显示图片,保存图片
//read
Mat image;
image =imread("1.png",1);
if (image.data==0) //读数据失败
//write
imwrite( "../../images/Gray_Image.jpg", gray_image );
//show
namedWindow( "color image", CV_WINDOW_AUTOSIZE );
imshow( "color image", image );
//convert BGR to Gray
//颜色转换函数 :从源image,到目gray_image, 宏CV_BGR2GRAY规定了颜色变换方法
cvtColor( image, gray_image, CV_BGR2GRAY );
2:图片对象之间的reference and copy
//reference
Mat A, C; // creates just the header parts
A = imread(argv[1], CV_LOAD_IMAGE_COLOR); // here we'll know the method used (allocate matrix)
Mat B(A); // Use the copy constructor
C = A; // Assignment operator
//如上A,B,C都是指向同一个数据matrix,操作其中一个,同时会影响其它的数据
//但是A,B,C有不同的header,所以 这些不同的header可以指向matrix中的一个子数据集
//ROI:region of interest
//如下,截取一张图片中的一部分数据 的方法
Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle
Mat E = A(Range::all(), Range(1,3)); // using row and column boundaries
//copy
Mat F = A.clone();
Mat G;
A.copyTo(G);
/*
注意:图片的容器使用了Mat对象,Mat对象由header和data组成
header是图片的信息:size and address pointer部分
data是图片的颜色信息
*/
3:老式函数cvLoadImage打开图片的方法
//加载显示
IplImage* img = cvLoadImage("13.png", 1);
Mat mtx(img); // convert IplImage* -> Mat
namedWindow("Display Image", WINDOW_AUTOSIZE );
//将image图片在Display Image这个窗口中显示
imshow("Display Image", mtx);
cvWaitKey(0);//wait for ur enter press on the picture
4:图像颜色数据在内存中的存储方式
图片就是一个平面矩阵,所以只要知道了行列坐标,就可以读 写对应位置的像素值了,
如果是灰度图像,每个位置坐标上就只有一个值(用来表示灰度颜色)
如果是多通道的图像,每个位置上,就有BGR三个值(用来表示彩色图像的三个分量)
当在图像数据加载到内存中时:由于内存地址是线性连续的,所以图像的存储方式也变成了线性的,线性存储也有利于快速的访问颜色数据(一个接一个的访问,确实会快点)
面使用image.isContinuous();这个函数来确定图像数据的存储在内存中是不是连续的。
Mat image=imread(argv[1],1);
if (image.data==0)
{
cerr<<"invalid image file to read!"<<endl;
return 0;
}
//得到颜色数据在内存空间中存放时,是否 线性是连续的
image.isContinuous(); // 1:连续 0:不连续
4:Mat::depth()函数
if(image.depth()==CV_8U) //查看图像中,每个通道的颜色数据 的深度,
//如我们常用的 BGR三通道,每个通道的值的范围为0-255,那么就说颜色深度为8位
颜色深度就是表示 每个通道颜色的数据用了多少位,用如下几个宏表示:
CV_8U CV_16U
CV_8S CV_16S CV_32S
CV_32F CV_64F
CV_Assert(image.depth() == CV_8U);//保证传入数据为true才能进行下面操作,否则会退出程序,而且会有下面的报错,并且显示在源程序中哪一行出错!非常好的debug函数
OpenCV Error: Assertion failed
下面的方法中,5,6,7,都是可以灵活的操作每个通道的数据,用的比较多的是方法5,效率也高点!
5:遍历图像中每个像素的方法
//方法1:
Mat image=imread("1.png",1);
CV_Assert(image.depth() == CV_8U); //0==0
int channels=image.channels(); //得到图像有多少个颜色通道
int rows=image.rows; //得到图像有多少行
int cols=image.cols; //得到图像有多少列
cols=cols*channels; //列数xchannel数,才是更底层的图像的真实列数
unsigned char *pt; //用来指向 每个颜色通道的 指针,用这个指针来读到每个像素的颜色值,当然改变像素值也是写这个指针指向的数值
for (int i=0;i<rows;i++)
{
pt=image.ptr<unsigned char>(i);
for (int j=0;j<cols;j++)
{
pt[j]=tables[pt[j]];
}
}
//小技巧:加快程序读写数据的速度
if (image.isContinuous())//如果颜色数据在内存中存放时,是连续存放的
{
rows=1; //row=0
cols=cols*rows; //cols=0 ...一直到最后一个像素的颜色数据位置
}
//注意 :一定不要把 cols=cols*channels;这一条忘记了,非常重要。
//方法2:
if (image.isContinuous())
{
uchar* p = image.data;//得到data数据的首地址,
for( unsigned int i =0; i < ncol*nrows; ++i)
{
*p= table[*p];
p++;
}
}
6:使用iterator(迭代器访问图片中的每一个像素)
// accept only char type matrices
CV_Assert(I.depth() == CV_8U);
const int channels = I.channels();
switch(channels)
{
case 1:
{
MatIterator_<uchar> it, end;
for( it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it)
*it = table[*it];
break;
}
case 3:
{
MatIterator_<Vec3b> it, end;
for( it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; ++it)
{
(*it)[0] = table[(*it)[0]];//可以方便的对每个像素,三个通道进行操作
(*it)[1] = table[(*it)[1]];
(*it)[2] = table[(*it)[2]];
}
}
}
7:on the fly(在运行过程中实时地址计算,最慢的方法)的访问像素的方法
// accept only char type matrices
CV_Assert(I.depth() == CV_8U);
const int channels = I.channels();
switch(channels)
{
case 1:
{
for( int i = 0; i < I.rows; ++i)
for( int j = 0; j < I.cols; ++j )
I.at<uchar>(i,j) = table[I.at<uchar>(i,j)];
break;
}
case 3:
{
Mat_<Vec3b> _I = I; //注意这里的新对象为 Mat_ (有下划线哦)
for( int i = 0; i < I.rows; ++i)
for( int j = 0; j < I.cols; ++j )
{
_I(i,j)[0] = table[_I(i,j)[0]];
_I(i,j)[1] = table[_I(i,j)[1]];
_I(i,j)[2] = table[_I(i,j)[2]];
}
I = _I;
break;
}
}
8:使用core function中的lookuptable,最快的方法改变图像中的每个像素
Mat lookUpTable(1, 256, CV_8U);
uchar* p = lookUpTable.data;
for( int i = 0; i < 256; ++i)
p[i] = table[i]; //把我们之前的tables写到 Mat类型的对象中
LUT(I, lookUpTable, J); //I是输入的图像,J是改变后的图像,
//不能地每个通道做灵活的操作
//LUT的操作过程就是使用 原始图像的 颜色值作为 index,在lookuptable中查到新的颜色值,
//注意 :这种方法OpenCV,做过优化,所以是最快的方法。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。