1、一:Opencv2与opencv1的区别: Opencv1.0版本于2006年面世,主要基于C语言。2009年发布opencv2,主要基于C++。此时opencv库被划分成多个模块,这些模块被编译成库文件后,位于lib文件夹中。主要有以下模块(版本1的结构见我的这篇blog: Opencv_core模块:包含核心功能,尤其是底层数据结构和算法函数。 Opencv_improc模块:包含图像处理函数。 Opencv_highgui模块:包含读写图像及视频的函数,以及操作图形用户界面函数。 Opencv_features2d模块:包含兴趣点检测子,描述子以及兴
2、趣点匹配框架。
Opencv_calib3d模块:包含相机标定,双目几何估计以及立体视觉函数。
Opencv_video模块:包含运动估算,特征跟踪以及前景提取函数与类。
Opencv_objdetect模块:包括物体检测函数,如脸部和行人检测。
库中还包含其它的工具模块,如机器学习(opencv_ml),计算几何(opencv_flann),第三方代码(opencv_contrib)等。这些模块都对有一个单独的头文件(位于include文件夹)。推荐的声明方式如下:
#include
3、de
4、
#include
5、 " << image.size().height << "," << image.size().width << endl; //size()返回的是一个结构体 namedWindow("show"); imshow("show", image); // 显示图片 imwrite("F:\\tongtong2.jpg", image); Mat result; flip(image,result, 0); namedWindow
6、"result",0); imshow("result", result); waitKey(0); return 0; } (2)Explaination: <1>opencv2中用于存储图像数据为Mat类型,而在opencv1中用IplImage(详细见我的这篇blog: <2>image.data是指向已分配的内存块的指针,当图片没有加载进来,则为NULL。 <3>image.size()返回的是一个结构体,实际上包括width和height这两个成员变量。 <4>flip(image,resu
7、lt,0); //其中正数表示水平反转,0表示垂直反转,负数表示既有水平又有垂直反转。 3)结果: 三:深浅拷贝 (1) 浅拷贝: Mat B; B = image ; // 第一种方式 Mat C(image); // 第二种方式 这两种方式称为浅copy,是由于它们有不同的矩阵头,但是它们共享内存空间,即指向一个矩阵。当图像矩阵发生变化时,两者相关联,都会变化。 (2) 深拷贝: Mat B,C; B = image.clone(); // 第一种方式 image.copyTo(C); // 第二种方式
8、
深拷贝是真正的copy了一个新的图像矩阵,此时image,B,C三者相互没有影响。
四:IplImage装换为Mat
IplImage*iplImage = cvLoadImage("F:\\11.jpg",1);
Mat image2(iplImage,false);
// 其中false为浅拷贝,而true为深拷贝,默认为false。此时注意需要释放iplImage
当然opencv提供了另外一种指针类,无需手动释放,但现在已经不用了,可以使用它来封装IplImage指针:
Ptr
9、Image("F:\\11.jpg",1);
图像遍历主要有三种方法,本节主要介绍和比较这三种方法。
一:简单存取像素值
首先介绍一个名词—椒盐噪点:它是一种特殊的噪点,它随机的将图像中的部分像素设置为白色或者黑色。
Code:
[cpp] view plaincopyprint?
#include 10、tream>
using namespace std;
using namespace cv;
void salt(Mat &image, int n)
{
for(int k = 0; k < n; k++)
{
rand();
int i = rand() % image.cols;
int j = rand() % image.rows;
if(image.channels() == 1)
{
11、 image.at 12、int n) // 这个只针对彩色三通道的图片
{
for(int k = 0; k < n; k++)
{
rand();
int i = rand() % image.cols;
int j = rand() % image.rows;
if(image.channels() == 3)
{
image(j,i)[0] = 255;
image(j,i)[1] = 255;
13、 image(j,i)[2] = 255;
}
}
}
int main()
{
Mat image = imread("F:\\huangrong.jpg", 1);
salt(image, 3000);
namedWindow("image");
imshow("image", image);
waitKey(0);
return 0;
}
Explaination:
(1) rand()是随机数生 14、成函数。
(2)image.at 15、重载了操作符(),允许我们可以通过它直接存取矩阵元素。
Result:
二:通过指针遍历图像
需要说明的是:一个宽为W,高为H的三通道图像需要填补一个大小由W*H*3个uchar构成的内存块。但是,出于效率的考虑,图像会在每行行尾填补一些额外的像素。这是因为,如果行的长度是4或8的倍数,一些多媒体处理芯片可以更高效的处理图像。
Mat中的成员函数isContinuous()可以判断这幅图像是否对行进行了填补。如果为真,则没有填补。
Code:
[cpp] view plaincopyprint?
/*通过指针遍历图像*/
#include 16、 17、 image.reshape(3, image.cols *image.rows);
cout << image.rows << endl;
cout << image.cols << endl;
}*/
int n1 = image.rows;
int nc = image.cols * image.channels();
if(image.isContinuous())
{
nc = n1 * nc;
n1 = 1;
18、}
for(int j = 0; j < n1; j++)
{
uchar *data = image.ptr(j);
//uchar *data = image.data + j * image.step; // 得到指向第i行的地址有两种方法 ptr是成员函数,而data是成员变量,不推荐使用data,易出错
for(int i = 0; i < nc; i++)
{
data[i] = data[i]/div *div + div/ 19、2;
}
}
cout << "一行含有的字节数:" << image.step << endl;
cout << "一个像素所含有的字节:" << image.elemSize() << endl;
cout << "通道数:" << image.channels()<< endl;
cout << "总像素个数:" << image.total() << endl;
cout << "width:" << image.size().width << endl;
cout 20、<< "width:" << image.cols << endl;
cout << "height:" << image.rows << endl;
}
void colorReduce2(const Mat &image, Mat &result, int div = 64)
{
int n1 = image.rows;
//int nc = image.cols * image.channels();
int nc = image.cols ;
for(int j = 0; j < n1; j++) 21、
{
//uchar *data = image.ptr(j);
//uchar *data_in = image.data + j * image.step; // 得到指向第i行的地址有两种方法 ptr是成员函数,而data是成员变量
//uchar *data_out = result.data + j * result.step;
for(int i = 0; i < nc; i++)
{
uchar *data = ima 22、ge.data + j * image.step + i * image.elemSize(); // 这种方式不推荐使用,一方面容易出错,还不适用于带有"感兴趣区域"
//data_out[i] = data_in[i]/div *div + div/2;
data[0] = 0;
data[1] = 0;
data[2] = 0;
}
}
}
int main()
{
Ma 23、t image = imread("F:\\huangrong.jpg", 1);
Mat result;
result.create(Size(image.cols, image.rows),image.type()); // create函数为result创建一个与输入图像的尺寸和类型完全相同的矩阵
//colorReduce2(image, result);
colorReduce(image);
namedWindow("image");
imshow("image", image);
/ 24、/namedWindow("result");
//imshow("result", result);
waitKey(0);
return 0;
}
Explaination:
(1) 得到指向第j行的地址有两种方法: image.ptr(j)是成员函数,而data是成员变量image.data+ j * image.step;但后面一种方法复杂点,推荐使用前者。
(2)成员变量step,rows,cols,成员函数elemSize,channels,total,size,create等解释见代码注释。
Result:
25、
三:通过迭代器遍历图像
C++中迭代器不熟的可以看看我转载的一篇blog:
Code:
[cpp] view plaincopyprint?
#include 26、at &image, int div = 64)
{
//Mat_ 27、t)
{
(*it)[0] = (*it)[0]/div * div + div/2;
(*it)[1] = (*it)[1]/div * div + div/2;
(*it)[2] = (*it)[2]/div * div + div/2;
}
}
void colorReduce2(Mat_ 28、ator
//Mat_ 29、
(*it)[1] = (*it)[1]/div * div + div/2;
(*it)[2] = (*it)[2]/div * div + div/2;
}
}
int main()
{
Mat image = imread("F:\\huangrong.jpg", 1);
if(!image.data){
cout << "fail to load image" << endl;
return 0;
}
colo 30、rReduce(image);
namedWindow("image");
imshow("image", image);
waitKey(0);
return 0;
}
Explaination:
(1)定义迭代器有两种方法:
MatIterator_ 31、开始和结束位置也有两种方法:
image.begin 32、encv中提供了两个非常实用的函数getTickCount()和getTickFrequency()可以非常方便的计算一段代码运行的时间;
代码:
[cpp] view plaincopyprint?
void timeCalc(Mat &image){
double duration;
duration = static_cast 33、getTickCount()) - duration;
duration /= getTickFrequency(); // 运行时间,以ms为单位 //CPU 每ms滴答的次数
}
首先讲下:
static_case 34、般用来对随机位置的像素进行读写,并不适合用来遍历图像。遍历一般用指针。最后需要说明的是一次性处理一个像素的三个通道比循环处理每个通道所花费的时间要少,效率要高。
一:邻域操作
以下例子主要对图像进行锐化。基于拉普拉斯算子<后面讨论>。这幅图像的边缘部分将得到放大,细节部分将更加的锐利。计算方式为:
sharpened_pixel = 5*current – left – right –up – down.
Code:
[cpp] view plaincopyprint?
#include 35、lude 36、 {
const uchar *previous = image.ptr 37、ge.cols - 1; i++)
{
if(image.channels() == 1) // 黑白图像
{
output[i] = saturate_cast 38、 {
*(output + i*image.elemSize()) =saturate_cast 39、lemSize() + 1) = saturate_cast 40、cast 41、annels * (image.cols - 1); ++i)
{
*output ++ = saturate_cast 42、);
result.col(0).setTo(Scalar(0,0,0));
result.col(result.cols - 1).setTo(Scalar(0));
return;
}
void sharpen2D(const Mat &image, Mat &result)
{
Mat kernel(3, 3, CV_32FC1, Scalar(0));
kernel.at 43、
kernel.at 44、
return;
}
int main()
{
Mat image = imread("F:\\huangrong.jpg", 0);
Mat result;
cout << image.depth() << endl;
result.create(Size(image.cols, image.rows), image.type());
sharpen(image, result);
//sharpen2D(image, result);
namedWindow 45、"image");
imshow("image", image);
namedWindow("result");
imshow("result", result);
waitKey(0);
return 0;
}
Explaination:
(1) saturate_cast 46、 << 0, -1.0, 0.0, -1.0, 5.0, -1.0, 0,-1.0, 0);
//opencv中简单初始化只有几个像素的mat类型
(3) result.row(0).setTo(Scalar(0));
//可以将矩阵的第0行所有像素全部设置为0
(4)opencv中自带了filter2D这个函数可以进行领域操作,其结果是一样的,在某些情况下回更高效点。
Result:
二:算术操作
Code:
[cpp] view plaincopyprint?
#include 47、clude 48、age*0.5 + image2*0.5 + 0.3; // 大多数算术函数在opencv2中都有对应的重载操作符
return result;
}
Mat addWeight2(Mat &image, Mat &image3)
{
Mat result;
vector 49、/ 将三个单通道图像合并为一个彩色三通道图像
return result;
}
int main()
{
Mat image = imread("F:\\huangrong.jpg", 1);
if(!image.data){
cout << "fail to load image" << endl;
return 0;
}
Mat image2 =Mat::zeros(image.rows, image.cols, image.type());
//Mat image2(image.rows, image.cols, image.ty






