Mat矩阵中每一个元素代表一个像素,灰度图像,像素用8U 无符号数,0黑色,255白色;彩色图像,每个像素需要3位这样的8U表示,即三个通道(R、G、B),矩阵依次存储一个像素的三个通道值,然后再存储下一个像素点。
灰度图像素类型uchar; 彩色图像素点类型Vec3b
计时
double time0 = static_cast<double>(getTickCount());
{
}
time0 = ((double)getTickCount()-time0)/getTickFrequency();
压缩颜色空间
在一幅数字图像存储的矩阵一般是uchar类型,为8位256个值。如果是三通道图形,那么应该有256*256*256=16581375种不同的颜色,这1600多万种颜色,数据量会很大,影响后期的处理,这个时候,我们就需要将颜色空间进行缩减。
对于三通道图像,本来有256*256*256种颜色,这里我们取:
0-9的像素取值:0
10-19的像素取值:1
……
250-256的像素取值:25
本节对应数学表达公式:I(x,y)= I(x,y)/div *div + div/2;
主程序
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
//颜色空间缩减函数
void colorreduce(Mat& input, Mat& output, int div);
int main()
{
//原图像
Mat src = imread("dota.png");
imshow("原图像", src);
//生成图像
Mat dest;
dest.create(src.rows, src.cols, src.type());
//颜色缩减
double time0 = static_cast<double>(getTickCount());
colorreduce(src, dest, 64);
time0 = ((double)getTickCount() - time0) / getTickFrequency();
cout << "运行时间" << time0 << "秒" << endl;
imshow("生成图像", dest);
waitKey();
return 0;
}
1、迭代器
void colorreduce(Mat& input, Mat& output, int div)
{
output = input.clone();
//迭代器
MatIterator_<Vec3b> it, end;
//或者Mat_<Vec3b>::iterator it, end;
it = output.begin<Vec3b>();
end = output.end<Vec3b>();
for (; it < end; 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;
}
}
2、指针
提供ptr函数访问任意一行像素的首地址,特别方便图像的一行一行的横向访问。
速度很快。
//获取像素指针
uchar * p = output.ptr<uchar>(i);
Vec3b * p = output.ptr<Vec3b>(i);
void colorreduce(Mat& input, Mat& output, int div)
{
output = input.clone();
int row = input.rows;
int cols = input.cols*input.channels();//每一行元素个数
for (int i = 0; i < row; i++)
{
//需要在output上进行更改
uchar* data = output.ptr<uchar>(i);
for (int j = 0; j < cols; j++)
{
data[j] = data[j] / div*div + div / 2;
}
}
}
或者
//彩色图
for (int i = 0; i < colorim.rows; ++i)
{
//获取第 i 行首像素指针
Vec3b * p = colorim.ptr<Vec3b>(i);
for (int j = 0; j < colorim.cols; ++j)
{
//三通道
p[j][0] = i % 255; //Blue
p[j][1] = j % 255; //Green
p[j][2] = 0; //Red
}
}
3、 用动态地址计算配合at访问像素
void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{
outputImage = inputImage.clone();
int rowNumber = outputImage.rows;
int colNumber = outputImage.cols;
for (int i = 0; i < rowNumber; i++)
{
for (int j = 0; j < colNumber; j++)
{
outputImage.at<Vec3b>(i, j)[0] = outputImage.at<Vec3b>(i, j)[0] / div*div + div / 2; //蓝色通道
outputImage.at<Vec3b>(i, j)[1] = outputImage.at<Vec3b>(i, j)[1] / div*div + div / 2; //绿色通道
outputImage.at<Vec3b>(i, j)[2] = outputImage.at<Vec3b>(i, j)[2] / div*div + div / 2; //红色通道
}
}
}