Scanning an image with pointers
使用指针扫描图像。这章与下一章展示两种不同的方式来实现图像扫描循环。书中给出的例子是减少图像颜色数量。一般的彩色图像由3个通道的像素组成,每个值为8位unsigned char。也就是说色彩总数为255*255*255.所以有时候图像处理的时候需要减少颜色数量以达到减少分析复杂度的目的。一个最简单的方式就是将RGB空间细分到更小的大小相等的多位数据集。例如,每个维度减少8,那么将得到一个总数为32*32*32个颜色。原图中的颜色将分配一个新的颜色值,形成这张色彩减少的图。
因此,基本的颜色减少算法很简单。设N为减少量因子,每个通道的每个像素值除以N(整型除法,精度会丢失)。然后再将结果与N相乘,会得到在输入像素值之下的乘积结果(这里的英文原文是this will give you the multiple of N just below the input pixel value)。加上N/2们正好得到临近两个N积的中间值。重复这个过程就能得到256/N*256/N*256/Nd的颜色值了。
可能这样写我自己都很难理解我想表达的意思。确实这里理解起来挺绕,我看了好久没整明白。不过如果按照他给的程序单步调试着看结果就能明白了。
void colorReduce(cv::Mat &image,int div=64)
div是减少量因子。
// 0202scaning an image with pointers.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "iostream"
using namespace std;
void colorReduce(cv::Mat &image,int div=64)
{
int nl=image.rows;//number of lines--行数
int nca=image.cols;
int ncb=image.cols*2;
int nce=image.cols*3;
int nc=image.cols*image.channels();每行的像素值总数。这里为什么要使用image.cols*image.channels()会在后面解释。
for (int j=0;j<nl;j++)
{
uchar* data=image.ptr<uchar>(j);
for (int i=ncb;i<nce;i++)
{
data[i]=data[i]/div*div;
}
}
}
/*
in a color image,the first 3 bytes of the image data buffer gives the 3 color channel values of the upper left pixel.
the next 3 bytes are the values of the second pixel of the first row,and so on.
*/
int _tmain(int argc, _TCHAR* argv[])
{
cv::Mat image=cv::imread("../../lena.jpg");
colorReduce(image);
cv::namedWindow("result");
cv::imshow("result",image);
cv::waitKey(0);
return 0;
}
这里解释为什么使用cols*channels()。在彩色图像中,前3bytes的图像数据给出左侧的图像,接下来3bytes给出之后的居中的图像数据。如图
在
for (int i=ncb;i<nce;i++)
这里,i=0,i<nca。会看到
cv::Mat类提供了一模板方法ptr来返回某一行的地址
uchar* data=image.ptr<uchar>(j);