【opencv学习笔记七】访问图像中的像素与图像亮度对比度调整

时间:2022-10-03 21:03:24

今天我们来看一下如何访问图像的像素,以及如何改变图像的亮度与对比度。

在之前我们先来看一下图像矩阵数据的排列方式。我们以一个简单的矩阵来说明:

对单通道图像排列如下:

【opencv学习笔记七】访问图像中的像素与图像亮度对比度调整

对于双通道图像排列如下:

【opencv学习笔记七】访问图像中的像素与图像亮度对比度调整

那么对于三通道的RGB图像则为:

【opencv学习笔记七】访问图像中的像素与图像亮度对比度调整

知道了排列方式之后我们来讨论一下访问图像像素常用的三种方式:

1.使用指针访问;

2.使用迭代器访问;

3.使用动态地址访问;

为了比较一下三种方式的效率,我们介绍两个函数来统计一下每种方式所需的时间。

int64 getTickCount()函数:返回CPU自某个时间(如开启电脑)以来走过的时钟周期数。

double getTickFrequency()函数:返回每秒钟CPU走过的时钟周期数。

然后我们来看第一种方式。

1.使用指针访问图像像素:我们将输入图像img_src的每一个像素值加上50后赋值给输出图像img_dst。

 int main()
{
int c;
Mat img_src = imread("1.jpg");
Mat img_dst; namedWindow("原图");
namedWindow("处理图"); int channels = img_src.channels();//获取图像通道数
img_dst = img_src.clone(); double time1 = static_cast<double>(getTickCount());//获取开始处理前时间 for (int i = ; i < img_src.rows; i++)//访问图像行数据
{
uchar* p_data1 = img_src.ptr(i);//获取图像行首地址
uchar* p_data2 = img_dst.ptr(i);//获取图像行首地址
for (int k = ; k < img_src.cols*channels; k++)//获取图像列(含通道)
{
p_data2[k] = saturate_cast<uchar>(p_data1[k] + );//图像处理 //*p_data2++ = saturate_cast<uchar>((*p_data1++) + 100);//与上一行图像处理的等效方式
//*(p_data2 + k) = saturate_cast<uchar>(*(p_data1 + k) + 50);//同上
}
} double time2 = static_cast<double>(getTickCount());//获取结束处理时间 time1 = (time2 - time1) / getTickFrequency();//计算处理所用时间
cout << "指针访问像素时间(S):" << time1 << endl; while ()
{
imshow("原图", img_src);//显示图像
imshow("处理图", img_dst);//显示图像
c = waitKey();
if (c == || char(c) == 'q' || char(c) == 'Q')//按下Q键或者ESC键退出程序
break;
}
return ;
}

2.使用迭代器方式:

 int main()
{
int c;
Mat img_src = imread("1.jpg");
Mat img_dst; namedWindow("原图");
namedWindow("处理图"); int channels = img_src.channels();//获取图像通道数
img_dst = img_src.clone(); double time1 = static_cast<double>(getTickCount());//获取开始处理前时间 Mat_<Vec3b>::iterator it = img_src.begin<Vec3b>();//获取原图开始地址
Mat_<Vec3b>::iterator itend = img_src.end<Vec3b>();//获取原图结束地址
Mat_<Vec3b>::iterator it2 = img_dst.begin<Vec3b>();//获取输出图开始地址
for (; it != itend; ++it, ++it2)
{
for (int i = ; i < ; i++)
{
(*it2)[i] = saturate_cast<uchar>((*it)[i] + );//图像处理
}
} double time2 = static_cast<double>(getTickCount());//获取结束处理时间 time1 = (time2 - time1) / getTickFrequency();//计算处理所用时间
cout << "指针访问像素时间(S):" << time1 << endl; while ()
{
imshow("原图", img_src);//显示图像
imshow("处理图", img_dst);//显示图像
c = waitKey();
if (c == || char(c) == 'q' || char(c) == 'Q')//按下Q键或者ESC键退出程序
break;
}
return ;
}

3.动态地址方式:

 int main()
{
int c;
Mat img_src = imread("1.jpg");
Mat img_dst; namedWindow("原图");
namedWindow("处理图"); int channels = img_src.channels();//获取图像通道数
img_dst = img_src.clone(); double time1 = static_cast<double>(getTickCount());//获取开始处理前时间 for (int i = ; i < img_src.rows; i++)
{
for (int k = ; k < img_src.cols; k++)
{
for (int j = ; j < channels; j++)
{
img_dst.at<Vec3b>(i, k)[j] = saturate_cast<uchar>(img_src.at<Vec3b>(i, k)[j] + );
}
}
} double time2 = static_cast<double>(getTickCount());//获取结束处理时间 time1 = (time2 - time1) / getTickFrequency();//计算处理所用时间
cout << "指针访问像素时间(S):" << time1 << endl; while ()
{
imshow("原图", img_src);//显示图像
imshow("处理图", img_dst);//显示图像
c = waitKey();
if (c == || char(c) == 'q' || char(c) == 'Q')//按下Q键或者ESC键退出程序
break;
}
return ;
}

我们来看一下处理的结果吧:

【opencv学习笔记七】访问图像中的像素与图像亮度对比度调整

实例

下面我们来看一个完整调用三种方式的例子,我们定义三个函数Mat image_bright1(Mat src);Mat image_bright2(Mat src);Mat image_bright3(Mat src);分别用来用三种方式处理图片。

 //************头文件包含*************
#include "stdafx.h"
#include<iostream>
#include<opencv.hpp>//包含opencv的头文件
//*********************************** //************命名空间***************
using namespace cv;//使用opencv命名空间
using namespace std;
//*********************************** //************全局变量*************** //*********************************** //************全局函数***************
Mat image_bright1(Mat src);//使用指针访问像素 Mat image_bright2(Mat src);//使用迭代器访问像素 Mat image_bright3(Mat src);//使用动态地址访问像素
//*********************************** //************主函数*****************
int main()
{
int c;
Mat img_src = imread("1.jpg");
Mat img_dst1, img_dst2, img_dst3; namedWindow("原图",);
namedWindow("指针访问像素",);
namedWindow("迭代器访问像素",);
namedWindow("动态地址访问像素",); double time1 = static_cast<double>(getTickCount());
img_dst1 = image_bright1(img_src);//使用指针访问像素 double time2 = static_cast<double>(getTickCount());
img_dst2 = image_bright2(img_src);//使用迭代器访问像素 double time3 = static_cast<double>(getTickCount());
img_dst3 = image_bright3(img_src);//使用动态地址访问像素 double time4 = static_cast<double>(getTickCount()); time1 = (time2 - time1) / getTickFrequency();
time2 = (time3 - time2) / getTickFrequency();
time3 = (time4 - time3) / getTickFrequency(); cout << "指针访问像素时间(S):"<<time1<<endl;
cout << "迭代器访问像素时间(S):" << time2 << endl;
cout << "动态地址访问像素时间(S):" << time3 << endl; while ()
{
imshow("原图", img_src);//显示图像
imshow("指针访问像素", img_dst1);//显示图像
imshow("迭代器访问像素", img_dst2);//显示图像
imshow("动态地址访问像素", img_dst3);//显示图像 c = waitKey();
if (c == || char(c) == 'q' || char(c) == 'Q')//按下Q键或者ESC键退出程序
break;
} return ;
} //使用指针访问像素
Mat image_bright1(Mat src)
{
Mat dst;
int channels = src.channels();
dst = src.clone(); for (int i = ; i < src.rows; i++)
{
uchar* p_data1 = src.ptr(i);
uchar* p_data2 = dst.ptr(i); for (int k = ; k < src.cols*channels; k++)
{
//*p_data2++ = saturate_cast<uchar>((*p_data1++) + 100);
//*(p_data2 + k) = saturate_cast<uchar>(*(p_data1 + k) + 50);
p_data2[k] = saturate_cast<uchar>(p_data1[k] + );//输出图像像素=原图像像素+50
}
}
return dst;
} //使用迭代器访问像素
Mat image_bright2(Mat src)
{
Mat dst;
dst = src.clone(); Mat_<Vec3b>::iterator it = src.begin<Vec3b>();
Mat_<Vec3b>::iterator itend = src.end<Vec3b>();
Mat_<Vec3b>::iterator it2 = dst.begin<Vec3b>();
for (; it != itend; ++it, ++it2)
{
for (int i = ; i < ; i++)
{
(*it2)[i] = saturate_cast<uchar>(*(*it)[i]);//输出图像像素=2*原图像像素
}
}
return dst;
} //使用动态地址访问像素
Mat image_bright3(Mat src)
{
Mat dst;
int channels = src.channels();
dst = src.clone();
for (int i = ; i < src.rows; i++)
{
for (int k = ; k < src.cols; k++)
{
for (int j = ; j < channels; j++)
{
dst.at<Vec3b>(i, k)[j] = saturate_cast<uchar>(*src.at<Vec3b>(i, k)[j] + );//输出图像像素=2*原图像像素+50
}
}
}
return dst;
}

结果:

【opencv学习笔记七】访问图像中的像素与图像亮度对比度调整

【opencv学习笔记七】访问图像中的像素与图像亮度对比度调整

【opencv学习笔记七】访问图像中的像素与图像亮度对比度调整
【opencv学习笔记七】访问图像中的像素与图像亮度对比度调整

【opencv学习笔记七】访问图像中的像素与图像亮度对比度调整

从时间上我们可以看出来,使用指针的速度是最快的。

有些童鞋应该已经看出来了,在三种方法中我们将图像像素的处理方法变了一下,得出的图像也不一样了。在三种方法中我们处理像素的计算方式分别为:

  • 输出图像像素=原图像像素+50;
  • 输出图像像素=2*原图像像素;
  • 输出图像像素=2*原图像像素+50;

其实这就是处理亮度与对比度的方法,从图像上也能看出来。

总结一下:g(x)=k*f(x)+b;其中g(x)为输出图像,f(x)为输入图像;

  • 调节k的值则可以改变图像的对比度;
  • 调节b的值则可以改变图像的亮度;

下载

功能很简单,代码很少,建议自己写一下或者在博文中复制一下,当然实在是懒的不要不要的土豪可以去下面的连接直接下载。

【opencv学习笔记七】访问图像中的像素与图像亮度对比度调整