opencv获取mat的指针_6、OpenCV中几种访问图像数据的方式

本文介绍了在OpenCV中三种访问和修改图像数据的方法:at函数、指针访问和查找表。通过实例展示了如何对三通道和单通道图像进行快速操作,其中查找表方式速度最快。此外,还提及了迭代器和isContinuous()方法,但未详细展开。
摘要由CSDN通过智能技术生成

在上一次中的最后,提到了修改图像数据的操作。但是,这种操作是比较慢的。下面说一下访问图像数据的几种方式。毕竟在实际的图像处理中,时刻少不了要自己写算法,这就必须访问图像数据,而快的访问方式可以大大提高效率。下面的例子中,还以修改图像数据为例。这些例子中,都通过用255减去原像素值来修改图像数据。其实这种操作就是反色操作。

例9-1 第一种修改方式,使用at访问修改像素值,这就是上次的例8,现在加上处理时间放在这里。

#include <opencv2/opencv.hpp>
#include <iostream>
 
using namespace cv;
using namespace std;
 
int main(int argc, char** argv)
{
 Mat src = imread("E:/1.jpg", 1);
 Mat modifyImg = Mat(src.size(), src.type());//新建一个与src大小、类型相同的空白图像
 namedWindow("例9_1原图", 0);
 imshow("例9_1原图", src);
 double time0 = static_cast<double>(getTickCount());
 int height = src.rows;//图片的高度
 int width = src.cols;//图片的宽度
 for (int i = 0; i < height; i++)
 {
 for (int j = 0; j < width; j++)
 {
 modifyImg.at<Vec3b>(i, j)[0] = 255 - src.at<Vec3b>(i, j)[0];
 modifyImg.at<Vec3b>(i, j)[1] = 255 - src.at<Vec3b>(i, j)[1];
 modifyImg.at<Vec3b>(i, j)[2] = 255 - src.at<Vec3b>(i, j)[2];
 }
 }
 time0 = ((double)getTickCount() - time0) / getTickFrequency();
 cout << "使用at的运行时间为:" << time0 << "秒" << endl;
 namedWindow("例9_1修改图", 0);
 imshow("例9_1修改图", modifyImg);
 waitKey(0);
 return 0;
}

dcb2023f7638b275b1f747fec84ed872.png

例9-2第二种修改方式,使用指针访问修改像素值

#include <opencv2/opencv.hpp>
#include <iostream>
 
using namespace cv;
using namespace std;
 
int main(int argc, char** argv)
{
 Mat src = imread("E: /1.jpg", 1);
 Mat modifyImg = Mat(src.size(), src.type());//新建一个与src大小、类型相同的空白图像
 namedWindow("例9_2原图", 0);
 imshow("例9_2原图", src);
 double time0 = static_cast<double>(getTickCount());
 ///通过指针访问像素值
 int height = src.rows;//图片的高度
 int width = src.cols;//图片的宽度
 int step = src.cols * src.channels();
 for (int i = 0; i < height; i++)
 {
 uchar* data = src.ptr<uchar>(i);
 uchar* mdData = modifyImg.ptr<uchar>(i);
 for (int j = 0; j < step; j++)
 {
 mdData[j] = saturate_cast<uchar>(255 - data[j]);
 }
 }
 time0 = ((double)getTickCount() - time0) / getTickFrequency();
 cout << "使用指针运行时间为:" << time0 << "秒" << endl;
 namedWindow("例9_2修改图", 0);
 imshow("例9_2修改图", modifyImg);
 waitKey(0);
 return 0;
}

f5bbf43ceca48fbf99ce4a2af6d73bba.png

例9-3第三种修改方式,使用查找表访问修改像素值

#include <opencv2/opencv.hpp>
#include <iostream>
 
using namespace cv;
using namespace std;
 
int main(int argc, char** argv)
{
 Mat src = imread("E: /1.jpg", 1);
 Mat modifyImg = Mat(src.size(), src.type());//新建一个与src大小、类型相同的空白图像
 namedWindow("例9_原图", 0);
 imshow("例9_原图", src);
 double time0 = static_cast<double>(getTickCount());
 ///通过查找表访问像素值,三通道图像
 // 建立LUT
 uchar LutTable[256 * 3];
 for (int i = 0; i < 256; ++i)
 {
 LutTable[i * 3] = 255 - i;
 LutTable[i * 3 + 1] = 255 - i;
 LutTable[i * 3 + 2] = 255 - i;
 }
 Mat lookUpTable(1, 256, CV_8UC3, LutTable);
 // 应用索引表进行查找
 LUT(src, lookUpTable, modifyImg);
 time0 = ((double)getTickCount() - time0) / getTickFrequency();
 cout << "使用查找表运行时间为:" << time0 << "秒" << endl;
 namedWindow("例9_修改图", 0);
 imshow("例9_修改图", modifyImg);
 waitKey(0);
 return 0;
}

fadd633be9897eac2dc69c5b693fb255.png

从上面三种方式看,第一种方式速度是最慢的,指针访问比较快,而使用查找表速度是最快的。

上面都是对三通道图像的数据进行修改,同样的方式可以实现对单通道图像的访问。下面使用采用查找表和指针的方式对单通道图像进行像素值修改。

例9-4 利用查找表修改单通道图像数据

#include <opencv2/opencv.hpp>
#include <iostream>
 
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
 Mat src = imread("E: /1.jpg", 1);
 Mat src_gray;
 cvtColor(src, src_gray, COLOR_RGB2GRAY);
 Mat modifyImg = Mat(src_gray.size(), src_gray.type());//新建一个与src大小、类型相同的空白图像
 namedWindow("例9_4原图", 0);
 imshow("例9_4原图", src_gray);
 double time0 = static_cast<double>(getTickCount());
 ///通过查找表访问像素值,单通道图像
 // 建立LUT
 uchar LutTable[256];
 for (int i = 0; i < 256; ++i)
 {
 LutTable[i] = 255 - i;
 }
 Mat lookUpTable(1, 256, CV_8UC1, LutTable);
 // 应用索引表进行查找
 LUT(src_gray, lookUpTable, modifyImg);
 time0 = ((double)getTickCount() - time0) / getTickFrequency();
 cout << "使用查找表处理单通道图像运行时间为:" << time0 << "秒" << endl;
 namedWindow("例9_4修改图", 0);
 imshow("例9_4修改图", modifyImg);
 waitKey(0);
 return 0;
}

20f9901bbf36ae692abddf592a17ea30.png

例9-5 利用指针修改单通道图像数据

#include <opencv2/opencv.hpp>
#include <iostream>
 
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
 Mat src = imread("E: /1.jpg", 1);
 Mat src_gray;
 cvtColor(src, src_gray, COLOR_RGB2GRAY);
 Mat modifyImg = Mat(src_gray.size(), src_gray.type());//新建一个与src_gray大小、类型相同的空白图像
 namedWindow("例9_5原图", 0);
 imshow("例9_5原图", src);
 
 double time0 = static_cast<double>(getTickCount());
 ///通过指针访问像素值
 int height = src_gray.rows;//图片的高度
 int width = src_gray.cols;//图片的宽度
 int step = src_gray.cols * src_gray.channels();
 for (int i = 0; i < height; i++)
 {
 uchar* data = src_gray.ptr<uchar>(i);
 uchar* mdData = modifyImg.ptr<uchar>(i);
 for (int j = 0; j < step; j++)
 {
 mdData[j] = saturate_cast<uchar>(255 - data[j]);
 }
 }·
 time0 = ((double)getTickCount() - time0) / getTickFrequency();
 cout << "使用指针处理单通道图像运行时间为:" << time0 << "秒" << endl;
 namedWindow("例9_5修改图", 0);
 imshow("例9_5修改图", modifyImg);
 waitKey(0);
 return 0;
}

884c619b3c5233c1f09a8336d44bef71.png

可以看出,采用指针和查找表的方式访问和修改像素值是比较快的方式。尤其是查找表,速度极快。对应上面例子的图像比较大,为3120X4160大小。由于担心初学者运行不出结果,所以每次小改动都放上了全部代码,毕竟十几年前我也是这么过来的。

除了上面几种方式之外,还有采用迭代器的方式以及操作连续图像块(isContinuous())的方式。其中迭代器的方式是最慢的,这里就不再举例,isContinuous()方式需要图像是连续存储的。在此也不再说明。有兴趣的可以自己试一试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值