天天看点

opencv学习之-----使用指针遍历图像

用一个简单的任务举例如何遍历图像:减少一幅图像的颜色数.

彩色图像是由三个通道的像素组成的.每个通道的亮度值分别对应三原色(红绿蓝).因为这些值是8位unsigned char类型的,总共的颜色数为256×256×256,总共超过了一千六百万种颜色.因此,为了减少分析图像的复杂性,有时减少图像的颜色数是有用的.一个简单的方法是把RGB颜色空间再分成相等大小的空间.例如,如果图像颜色减少为每8个像素取一个像素值,你最终只会得到32×32×32种颜色.原始图像中的每一种颜色被减少后的图像新的颜色值代替,这个新的颜色值是,它原来属于小的颜色空间的中间值.

因此,这个基本的颜色缩减算法是很简单的.如果N是缩减因子,然后对图像中的每个像素,然后这个像素的每个通道的值除以N(整除,因此需要注意有数据丢失).然后把这个结果乘以N,最后的结果会略小于输入的像素值.然后再加加上N/2,会得到在两个与N相乘相邻区间的中间值.对于每个8位通道重复这个处理,你会得到总共256/N×256/N×256/N可能的颜色值.

#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>

void colorReduce(cv::Mat& image, int div = 64)
{
	int nr = image.rows; //行数
	int nc = image.cols * image.channels(); //每行元素的个数

	int n = static_cast<int>(cv::log(static_cast<double>(div)) / cv::log(2.0));
	uchar mask = 0xFF << n;  //用来对像素取整的掩膜

	for (int i = 0; i<nr; i++)
	{
		uchar* data = image.ptr<uchar>(i);//得到对i行的首地址
		for (int j = 0; j<nc; j++) //处理每一个像素
		{
			//*data++ = *data - *data % div + div / 2;
			*data++ = (*data & mask) + div / 2;
		}
	}

}


int main(int argc, char** argv)
{

	cv::Mat img = cv::imread("8.jpg");
	cv::Mat img2 = img.clone();

	double duration;
	duration = static_cast<double>(cv::getTickCount());

	colorReduce(img2);
	duration = static_cast<double>(cv::getTickCount()) - duration;
	duration /= cv::getTickFrequency();

	cv::namedWindow("original");
	cv::imshow("original", img);
	cv::namedWindow("altered");
	cv::imshow("altered", img2);

	std::cout << duration << std::endl;

	cv::waitKey(0);
	return 0;

}
           

原始图像:

opencv学习之-----使用指针遍历图像

运行结果如下:

opencv学习之-----使用指针遍历图像