opencv4.5.1 C++ 指针遍历操作像素图像出现周期性条纹的问题解决

最近在使用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后的图像

三种赋值方法的结果

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
心中带点小风骚的头像心中带点小风骚普通用户
上一篇 2022年5月12日
下一篇 2022年5月12日

相关推荐