赞
踩
这种方式基于.ptr的操作,也是比较推荐的遍历图像的方式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
/** @Method 1: the efficient method
accept grayscale image and RGB image */
int
ScanImageEfficiet(Mat & image)
{
// channels of the image
int
iChannels = image.channels();
// rows(height) of the image
int
iRows = image.rows;
// cols(width) of the image
int
iCols = image.cols * iChannels;
// check if the image data is stored continuous
if
(image.isContinuous())
{
iCols *= iRows;
iRows = 1;
}
uchar* p;
for
(
int
i = 0; i < iRows; i++)
{
// get the pointer to the ith row
p = image.ptr<uchar>(i);
// operates on each pixel
for
(
int
j = 0; j < iCols; j++)
{
// assigns new value
p[j] = table[p[j]];
}
}
return
0;
}
|
相较于高效的方式需要自己来计算需要遍历的数据量,以及当图像的行与行之间数据不连续的时候需要跳过一些间隙。迭代器(iterator)方式提供了一个更安全的访问图像像素的方式。你只需要做的就是声明两个MatIterator_变量,一个指向图像开始,一个指向图像结束,然后迭代。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
/** @Method 2: the iterator(safe) method
accept grayscale image and RGB image */
int
ScanImageIterator(Mat & image)
{
// channels of the image
int
iChannels = image.channels();
switch
(iChannels)
{
case
1:
{
MatIterator_<uchar> it, end;
for
(it = image.begin<uchar>(), end = image.end<uchar>(); it != end; it++)
{
*it = table[*it];
}
break
;
}
case
3:
{
MatIterator_<Vec3b> it, end;
for
(it = image.begin<Vec3b>(), end = image.end<Vec3b>(); it != end; it++)
{
(*it)[0] = table[(*it)[0]];
(*it)[1] = table[(*it)[1]];
(*it)[2] = table[(*it)[2]];
}
break
;
}
}
return
0;
}
|
这种方式不推荐用来遍历图像,一般用在要随机访问很少量的图像数据的时候。基本用法就是指定行列号,返回该位置的像素值。不过需要你事先知道返回的数据类型是uchar还是Vec3b或者其他的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
/** @Method 3: random access method
accept grayscale image and RGB image */
int
ScanImageRandomAccess(Mat & image)
{
// channels of the image
int
iChannels = image.channels();
// rows(height) of the image
int
iRows = image.rows;
// cols(width) of the image
int
iCols = image.cols;
switch
(iChannels)
{
// grayscale
case
1:
{
for
(
int
i = 0; i < iRows; i++)
{
for
(
int
j = 0; j < iCols; j++)
{
image.at<uchar>(i, j) = table[image.at<uchar>(i, j)];
}
}
break
;
}
// RGB
case
3:
{
Mat_<Vec3b> _image = image;
for
(
int
i = 0; i < iRows; i++)
{
for
(
int
j = 0; j < iCols; j++)
{
_image(i, j)[0] = table[_image(i, j)[0]];
_image(i, j)[1] = table[_image(i, j)[1]];
_image(i, j)[2] = table[_image(i, j)[2]];
}
}
image = _image;
break
;
}
}
return
0;
}
|
OpenCV大概也考虑到了有很多这种需要改变单个像素值的场合(比如基于单个像素值的亮度变换,gamma矫正等),因此在core模块提供了一个更加高效很一颗赛艇的LUT()函数来进行这种操作而且不需要遍历整个图像。
首先建个映射查找表:
1
2
3
4
5
6
7
|
// build a Mat type of the lookup table
Mat lookupTable(1, 256, CV_8U);
uchar* p = lookupTable.data;
for
(
int
i = 0; i < 256; i++)
{
p[i] = table[i];
}
|
1
2
|
// call the function
LUT(image, lookupTable, matout);
|
(1)直接通过cout<<mat<<endl;语句将所需输出的Mat矩阵输出到窗口;
(2)将mat中数据输出到xml文件中
FileStorage fs("./mat.xml",FileStorage::WRITE);
fs<<"mat"<<mat;
fs.release();
通过指针遍历mat中图像像素地址,依次输出
uchar * pdata=mat.ptr<uchar>(i);
for (int i=0;i<mat.rows;i++)
{
for (int j=0;j<mat.cols*mat.channels();j++)
{
cout<<padata[j]<<endl;
}
}
注意:由于mat中存储的像素数据是uchar或vec3d格式,直接通过cout<<padata[j]<<endl输出的话,将其数据对应的ASCII码进行输出,而有的数据ASCII码是隐藏的不对窗口显示,所以需要将数据类型进行转换再输出即可,如下:
int img_pixel=(int)padata[j];//像素中数据为0-255,所以使用int类型即可
cout<<padata[j]<<endl;
其余输出方式都是通过指针将mat中像素数据读取并转化再输出即可,只是获取指针方式不同而已。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。