1、存取像素值
举个栗子:图像中添加椒盐噪点
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
void salt(cv::Mat image, int n) //创建添加椒盐噪点的函数,第一个参数是张输入图像,传引用的参数传递方式,修改的像素个数
{
for (int k = 0; k < n; k++)
{
int i = std::rand() % image.cols;//像素的行号和列号通过随机函数得到
int j = std::rand() % image.rows;
//if (image.channels() == 1) 通过检查图像的通道数来区分灰度图像还是彩色图像
if (image.type() == CV_8UC1)//type()方法区分灰度图和彩色图像
{
image.at<uchar>(j, i) = 255; //<uchar>指定的数据类型
}
//if (image.channels() == 3)
else if (image.type() ==CV_8UC3)
{
image.at<cv::Vec3b>(j, i)[0] = 255;//at()方法访问像素,彩色图像像素是有三个8位数组成的向量(cv::Vec3b),三个通道都设置成255
image.at<cv::Vec3b>(j, i)[1] = 255;
image.at<cv::Vec3b>(j, i)[2] = 255;
}
}
}
int main()
{
cv::Mat image = cv::imread("boldt.jpg");
salt(image, 3000);
cv::imshow("image", image);
cv::waitKey(0);
return 0;
}
结果:
2、遍历图像像素的不同种方法
①栗子:减少图像中的颜色数目
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
//指针扫描图像
void colorReduce(cv::Mat image, int div = 64)
{
int nl = image.rows; //行数
int nc = image.cols*image.channels();//每行的操作个数
for (int j = 0; j < nl; j++)
{
uchar* data = image.ptr<uchar>(j); //取行的首地址
for (int i = 0; i < nc; i++)
{
data[i] = data[i] / div*div + div / 2; //像素的处理
}
}
}
②
//迭代器扫描图像
void colorReduce1(cv::Mat &image, int div = 64)
{
cv::Mat_<cv::Vec3b>::iterator it = image.begin < cv::Vec3b > ();//初始位置获得迭代器
cv::Mat_<cv::Vec3b>::iterator itend = image.end < cv::Vec3b >() ;//获得结位置
for (;it != itend; ++it)
{
(*it)[0] = (*it)[0] / div*div + div / 2;
(*it)[1] = (*it)[1] / div*div + div / 2;
(*it)[2] = (*it)[2] / div*div + div / 2;
}
}
③
//Mat提供了一个检测图像是否连续的函数isContinuous()。当图像连通时,我们就可以把图像完全展开,看成是一行。
void colorReduce2(const cv::Mat & image, cv::Mat & outImage, int div)
{
int nr = image.rows;
int nc = image.cols;
outImage.create(image.size(), image.type());
if (image.isContinuous() && outImage.isContinuous())
{
nr = 1;
nc = nc*image.rows*image.channels();
}
for (int i = 0; i<nr; i++)
{
const uchar* inData = image.ptr<uchar>(i);
uchar* outData = outImage.ptr<uchar>(i);
for (int j = 0; j<nc; j++)
{
* outData++ = *inData++ / div*div + div / 2;
}
}
}
④
//at<typename>(i,j) 时间最长
void colorReduce3(cv::Mat image, int div)
{
for (int i = 0; i<image.rows; i++)
{
for (int j = 0; j<image.cols; j++)
{
image.at<cv::Vec3b>(i, j)[0] = image.at<cv::Vec3b>(i, j)[0] / div*div + div / 2;
image.at<cv::Vec3b>(i, j)[1] = image.at<cv::Vec3b>(i, j)[1] / div*div + div / 2;
image.at<cv::Vec3b>(i, j)[2] = image.at<cv::Vec3b>(i, j)[2] / div*div + div / 2;
}
}
}
主函数:
int main()
{
cv::Mat image;
image = cv::imread("image.jpg");
cv::imshow("yuan", image);
//-----colorReduce
double time = static_cast<double>(cv::getTickCount());
colorReduce(image, 64);
time = (static_cast<double>(cv::getTickCount()) - time) / cv::getTickFrequency();
std::cout << "colorReduce = " << time << std::endl;
cv::namedWindow("colorReduce");
cv::imshow("colorReduce", image);
//-----colorReduce1
double time1 = static_cast<double>(cv::getTickCount());
colorReduce1(image, 64);
time1 = (static_cast<double>(cv::getTickCount()) - time1) / cv::getTickFrequency();
std::cout << "colorReduce1 = " << time1 << std::endl;
cv::namedWindow("colorReduce1");
cv::imshow("colorReduce1", image);
//-----colorReduce2
cv::Mat outImage;
outImage.create(image.size(), image.type());
double time2 = static_cast<double>(cv::getTickCount());
colorReduce2(image, outImage, 64);
time2 = (static_cast<double>(cv::getTickCount()) - time2) / cv::getTickFrequency();
std::cout << "colorReduce2 = " << time2 << std::endl;
cv::namedWindow("colorReduce2");
cv::imshow("colorReduce2", image);
//-----colorReduce3
double time3 = static_cast<double>(cv::getTickCount());
colorReduce3(image, 64);
time3 = (static_cast<double>(cv::getTickCount()) - time3) / cv::getTickFrequency();
std::cout << "colorReduce3 = " << time3 << std::endl;
cv::namedWindow("colorReduce3");
cv::imshow("colorReduce3", image);
cv::waitKey(0);
return 0;
}
各个遍历的时长: