最近在使用opencv做一些大数据量且快速的图像计算,程序需要经常遍历像素,所以我捡起以前的知识直接用Mat.data这个成员来做指针的操作。有时候会比它重载的运算符计算速度要快一些,而且在一些地方用的挺顺利的,直到我的结果图像出现了意想不到的问题。
过程
1.选取ROI图像
2.对ROI图像使用at()方法进行遍历,结果图像正确。
2.对ROI图像取Mat.data 进行指针遍历,图像出现问题。
原因
自从工作以来,使用opencv我一直都是能用就算,以实践为主,很少去深入研究深层原理。在这里我个人认为问题原因在于:选取的ROI取指针指向的内存是原图的内存位置,或者说ROI图像就是使用了原图的内存,原图并没有消失。 Mat.at()方法可以正确操作是因为此方法是基于生成ROI的索引来操作的,所以能取到目标的像素,而指针操作不正确则是由于它遍历的范围是原图的 p 到 p + N(其中uchar* p = Mat.data,N为像素数,或者说偏移量)的像素范围,所以会发生一个周期性的条纹现象。
简单画了一下图,大概是这个样子的:
图片我后面才想起来加,没有特意去测试,相当于我上面文字的图像表示吧。
解决
把ROI图像克隆到一个新的矩阵里,对这个新的矩阵进行操作。
最后
欢迎指正。
测试代码
#include <iostream>
#include <opencv2/opencv.hpp>
#ifdef _DEBUG
#pragma comment(lib, "opencv_world451d.lib")
#else
#pragma comment(lib, "opencv_world451.lib")
#endif
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
Mat src = imread("bird.jpg", IMREAD_GRAYSCALE); //读图
namedWindow("src", WINDOW_FREERATIO);
imshow("src", src);
waitKey(0);
Rect roi = Rect(500, 500, 2000, 2000); //定义ROI大小
Mat process = Mat(src, roi); //取ROI图像
namedWindow("process", WINDOW_FREERATIO);
imshow("process", process);
waitKey(0);
Mat dst1 = Mat::zeros(2000, 2000, CV_8UC1); //结果1
Mat dst2 = Mat::zeros(2000, 2000, CV_8UC1); //结果2
Mat dst3 = Mat::zeros(2000, 2000, CV_8UC1); //结果3
/*方法1*/
for (int i = 0; i < 2000; i++)
{
for (int j = 0; j < 2000; j++)
{
dst1.at<uchar>(i, j) = process.at<uchar>(i, j); //赋值
}
}
/*方法2*/
uchar* p_src = process.data;
uchar* p_dst2 = dst2.data;
for (int i = 0; i < 2000 * 2000; i++)
{
*(p_dst2 + i) = *(p_src + i); //赋值
}
namedWindow("dst1", WINDOW_FREERATIO);
imshow("dst1", dst1);
namedWindow("dst2", WINDOW_FREERATIO);
imshow("dst2", dst2);
waitKey(0);
/*方法2改正*/
Mat process_clone = process.clone();
uchar* p_src2 = process_clone.data;
uchar* p_dst3 = dst3.data;
for (int i = 0; i < 2000 * 2000; i++)
{
*(p_dst3 + i) = *(p_src2 + i); //赋值
}
namedWindow("dst1", WINDOW_FREERATIO);
imshow("dst1", dst1);
namedWindow("dst2", WINDOW_FREERATIO);
imshow("dst2", dst2);
namedWindow("dst3", WINDOW_FREERATIO);
imshow("dst3", dst3);
waitKey(0);
return 0;
}
测试结果
原图
取ROI后的图像
三种赋值方法的结果
文章出处登录后可见!
已经登录?立即刷新