OpenCV - 使用 for 循环访问 Mat 数据
OpenCV - Accessing Mat data using for loop
我正在尝试创建一个卷积函数,但在访问内核数据 (cv::Mat) 时遇到了问题。
我创建了 3x3 内核:
cv::Mat krn(3, 3, CV_32FC1);
krn.setTo(1);
krn = krn/9;
然后我尝试遍历它。接下来 image
Mat 将是我要应用卷积运算符的图像,输出将是卷积的结果:
for (int r = 0; r < image.rows - krn.rows; ++r) {
for (int c = 0; c < image.cols - krn.cols; ++c) {
int sum = 0;
for (int rs = 0; rs < krn.rows; ++rs) {
for (int cs = 0; cs < krn.cols; ++cs) {
sum += krn.data[rs * krn.cols + cs] * image.data[(r + rs) * image.cols + c + cs];
}
}
output.data[(r+1)*src.cols + c + 1]=sum; // assuming 3x3 kernel
}
}
但是输出并不如预期(只有随机的黑白像素)。
但是,如果我这样更改我的代码:
for (int r = 0; r < image.rows - krn.rows; ++r) {
for (int c = 0; c < image.cols - krn.cols; ++c) {
int sum = 0;
for (int rs = 0; rs < krn.rows; ++rs) {
for (int cs = 0; cs < krn.cols; ++cs) {
sum += 0.11 * image.data[(r + rs) * image.cols + c + cs]; // CHANGE HERE
}
}
output.data[(r+1)*src.cols + c + 1]=sum; // assuming 3x3 kernel
}
}
使用 0.11
而不是内核值似乎可以提供正确的输出。
出于这个原因,我认为我在访问内核数据时做错了。
P.S: 我不能使用 krn.at<float>(rs,cs)
.
谢谢!
cv::Mat::data
是 uchar
.
类型的指针
通过 data[y * cols + x]
,您可以访问 krn
中存储的 float
值的某些字节。要获得完整的浮点值,请使用 at
方法模板:
krn.at<float>(rs,cs)
考虑将 sum
变量的类型更改为实数。如果没有这个,你可能会在计算卷积时丢失部分结果。
所以,如果你不能使用at
,就从数据指针读取4个字节:
float v = 0.0;
memcpy(&v, krn.data + (rs * krn.step + cs * sizeof(float)), 4);
step
- 表示mat中一行占用的总字节数。
您可以 cast 指针,而不是不必要地使用 memcpy
。我将使用 C 风格的转换,因为为什么不呢。
cv::Mat krn = 1 / (cv::Mat_<float>(3,3) <<
1, 2, 3,
4, 5, 6,
7, 8, 9);
for (int i = 0; i < krn.rows; i += 1)
{
for (int j = 0; j < krn.cols; j += 1)
{
// to see clearly what's happening
uint8_t *byteptr = krn.data + krn.step[0] * i + krn.step[1] * j;
float *floatptr = (float*) byteptr;
// or in one step:
float *floatptr = (float*) (krn.data + krn.step[0] * i + krn.step[1] * j);
cout << "krn.at<float>(" << i << "," << j << ") = " << (*floatptr) << endl;
endl;
}
}
krn.at<float>(0,0) = 1
krn.at<float>(0,1) = 0.5
krn.at<float>(0,2) = 0.333333
krn.at<float>(1,0) = 0.25
krn.at<float>(1,1) = 0.2
krn.at<float>(1,2) = 0.166667
krn.at<float>(2,0) = 0.142857
krn.at<float>(2,1) = 0.125
krn.at<float>(2,2) = 0.111111
请注意,指针算法可能并不明显。如果你有一个 uint8_t*
,添加 1
将它移动 一个 uint8_t,如果你有一个 float*
,添加 1
将它移动 一个浮点数,即 四 字节。 step[]
包含以字节表示的偏移量。
有关详细信息,请参阅 the documentation,其中包括有关 step[]
数组的信息,该数组包含 strides/steps 以计算矩阵中给定索引元组的偏移量。
我正在尝试创建一个卷积函数,但在访问内核数据 (cv::Mat) 时遇到了问题。
我创建了 3x3 内核:
cv::Mat krn(3, 3, CV_32FC1);
krn.setTo(1);
krn = krn/9;
然后我尝试遍历它。接下来 image
Mat 将是我要应用卷积运算符的图像,输出将是卷积的结果:
for (int r = 0; r < image.rows - krn.rows; ++r) {
for (int c = 0; c < image.cols - krn.cols; ++c) {
int sum = 0;
for (int rs = 0; rs < krn.rows; ++rs) {
for (int cs = 0; cs < krn.cols; ++cs) {
sum += krn.data[rs * krn.cols + cs] * image.data[(r + rs) * image.cols + c + cs];
}
}
output.data[(r+1)*src.cols + c + 1]=sum; // assuming 3x3 kernel
}
}
但是输出并不如预期(只有随机的黑白像素)。 但是,如果我这样更改我的代码:
for (int r = 0; r < image.rows - krn.rows; ++r) {
for (int c = 0; c < image.cols - krn.cols; ++c) {
int sum = 0;
for (int rs = 0; rs < krn.rows; ++rs) {
for (int cs = 0; cs < krn.cols; ++cs) {
sum += 0.11 * image.data[(r + rs) * image.cols + c + cs]; // CHANGE HERE
}
}
output.data[(r+1)*src.cols + c + 1]=sum; // assuming 3x3 kernel
}
}
使用 0.11
而不是内核值似乎可以提供正确的输出。
出于这个原因,我认为我在访问内核数据时做错了。
P.S: 我不能使用 krn.at<float>(rs,cs)
.
谢谢!
cv::Mat::data
是 uchar
.
通过 data[y * cols + x]
,您可以访问 krn
中存储的 float
值的某些字节。要获得完整的浮点值,请使用 at
方法模板:
krn.at<float>(rs,cs)
考虑将 sum
变量的类型更改为实数。如果没有这个,你可能会在计算卷积时丢失部分结果。
所以,如果你不能使用at
,就从数据指针读取4个字节:
float v = 0.0;
memcpy(&v, krn.data + (rs * krn.step + cs * sizeof(float)), 4);
step
- 表示mat中一行占用的总字节数。
您可以 cast 指针,而不是不必要地使用 memcpy
。我将使用 C 风格的转换,因为为什么不呢。
cv::Mat krn = 1 / (cv::Mat_<float>(3,3) <<
1, 2, 3,
4, 5, 6,
7, 8, 9);
for (int i = 0; i < krn.rows; i += 1)
{
for (int j = 0; j < krn.cols; j += 1)
{
// to see clearly what's happening
uint8_t *byteptr = krn.data + krn.step[0] * i + krn.step[1] * j;
float *floatptr = (float*) byteptr;
// or in one step:
float *floatptr = (float*) (krn.data + krn.step[0] * i + krn.step[1] * j);
cout << "krn.at<float>(" << i << "," << j << ") = " << (*floatptr) << endl;
endl;
}
}
krn.at<float>(0,0) = 1
krn.at<float>(0,1) = 0.5
krn.at<float>(0,2) = 0.333333
krn.at<float>(1,0) = 0.25
krn.at<float>(1,1) = 0.2
krn.at<float>(1,2) = 0.166667
krn.at<float>(2,0) = 0.142857
krn.at<float>(2,1) = 0.125
krn.at<float>(2,2) = 0.111111
请注意,指针算法可能并不明显。如果你有一个 uint8_t*
,添加 1
将它移动 一个 uint8_t,如果你有一个 float*
,添加 1
将它移动 一个浮点数,即 四 字节。 step[]
包含以字节表示的偏移量。
有关详细信息,请参阅 the documentation,其中包括有关 step[]
数组的信息,该数组包含 strides/steps 以计算矩阵中给定索引元组的偏移量。