core组件之操作图像中的像素
来源:互联网 发布:台式机显卡80度 知乎 编辑:程序博客网 时间:2024/05/16 05:04
图像处理的基础是遍历图像的每一个像素点,即图像扫描。首先,要对图像矩阵在内存中的存储方式稍有了解。
对于单通道灰度图像,它的存储方式是这样的:
对于多通道图像,是这样的:
(注:图片来自Google。如键入“单通道图像”,然后google图片就有啦)
在本节中,我们要对图像进行颜色空间缩减。借由颜色空间缩减来展示三种遍历图像的方式。那么,什么是”颜色空间缩减“呢?
我们知道,对于元素类型为 uchar 的单通道图像矩阵,每个像素点有 256 个灰度值;对于三通道图像,每个像素点的颜色种类达 16777216 种(256*256*256)。如此多的颜色可能会对算法性能造成严重影响,我们往往只需要颜色的一部分,也能满足要求,因此引入了颜色空间缩减。
颜色缩减可以由一个简单的函数实现
pixelNew = pixelOld / div * div;
比如int div=32,那么0~31范围的像素值转换为0,32~63范围的像素值转换为1,…,224~255范围的像素值转换为7。最终,经过颜色缩减后,256*256*256种情况则会降低为8*8*8种情况。
三种遍历方式
(注:在下面的遍历中,颜色缩减函数采用pixelNew = pixelOld / div * div + div/2)
1、下标遍历
void colorReduce(Mat& inputImg, Mat& outImg, int div){ outImg = inputImg.clone(); int rowNum = outImg.rows; int colNum = outImg.cols*outImg.channels();//每一行的元素个数=列数*通道数 for (int i = 0; i < rowNum; ++i) { uchar* pdata = outImg.ptr<uchar>(i);//取出第i行的首地址 for (int j = 0; j < colNum; ++j) { pdata[j] = pdata[j] / div*div + div / 2;//颜色缩减 } }}
2、迭代器遍历
void colorReduce(Mat& inputImg, Mat& outImg, int div){ outImg = inputImg.clone(); Mat_<Vec3b>::iterator it = outImg.begin<Vec3b>(); while (it != outImg.end<Vec3b>()) { //因为是三通道的 (*it)[0] = (*it)[0] / div*div + div / 2; (*it)[1] = (*it)[1] / div*div + div / 2; (*it)[2] = (*it)[2] / div*div + div / 2; ++it; }}
3、结合at()函数遍历
void colorReduce(Mat& inputImg, Mat& outImg, int div){ outImg = inputImg.clone(); int rowNum = outImg.rows; int colNum = outImg.cols; for (int i = 0; i < rowNum; ++i) { for (int j = 0; j < colNum; ++j) { outImg.at<Vec3b>(i, j)[0] = outImg.at<Vec3b>(i, j)[0] / div*div + div / 2; outImg.at<Vec3b>(i, j)[1] = outImg.at<Vec3b>(i, j)[1] / div*div + div / 2; outImg.at<Vec3b>(i, j)[2] = outImg.at<Vec3b>(i, j)[2] / div*div + div / 2; } }}
测试:
#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <iostream>using namespace std;using namespace cv;void colorReduce(Mat& inputImg, Mat& outImg, int div);int main(){ Mat srcImg = imread("E:/image/dog.jpg"); imshow("srcImg", srcImg); Mat dstImg; double start = static_cast<double>(getTickCount()); colorReduce(srcImg, dstImg, 32); start = (static_cast<double>(getTickCount()) - start) / getTickFrequency(); cout << "duration = " << start << endl; imshow("dstImg", dstImg); waitKey(0); return 0;}
【注意】
以上每一个循环中都要计算一遍颜色缩减的函数,这是很费时的。正确的做法是,把颜色缩减的映射值先存在hashTable中,循环的时候直接去取就好了。
int div = 32;int hashTable[256] = { 0 };for (int i = 0; i < 256; ++i) { hashTable[i] = i / div*div;//先把像素值存到hashTable中,到时候就不用每一个循环都计算一遍了,直接从hashTable中取就好了}
循环内的做法就是(以下标遍历为例子):
pdata[j] = hashTable[pdata[j]];
【LUT函数】
不过,以上只是为了说明图像遍历而写的例子,如果是实现批量图像元素查找和更改,则推荐使用OpenCV内置的LUT函数。LUT函数的使用需要首先初始化上面的hashTable。然后,
Mat lookupTable(1, 256, CV_8U);uchar *p = lookupTable.data;for (int i = 0; i < 256; ++i) { p[i] = hashTable[i];}
LUT函数的定义
void LUT(InputArray src, InputArray lut, OutputArray dst);
测试:
#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <iostream>using namespace std;using namespace cv;int main(){ Mat srcImg = imread("E:/image/dog.jpg"); imshow("srcImg", srcImg); Mat dstImg; int div = 32; int hashTable[256] = { 0 }; for (int i = 0; i < 256; ++i) { hashTable[i] = i / div*div; } Mat lookupTable(1, 256, CV_8U); uchar *p = lookupTable.data; for (int i = 0; i < 256; ++i) { p[i] = hashTable[i]; } double start = static_cast<double>(getTickCount()); LUT(srcImg, lookupTable, dstImg); start = (static_cast<double>(getTickCount()) - start) / getTickFrequency(); cout << "duration = " << start << endl; imshow("dstImg", dstImg); waitKey(0); return 0;}
测试结果:
- core组件之操作图像中的像素
- 五.Core组件进阶(3.访问图像中的像素点)
- android学习笔记之图像像素操作
- 快速图像像素操作
- android 操作图像像素
- 图像像素操作
- OpenGL: 图像像素操作
- 图像像素操作
- 图像像素操作
- 图像像素操作
- opencv & qt study-(5)-操作图像中的像素
- Android游戏Graphics绘图之图像像素操作
- Android游戏Graphics绘图之图像像素操作
- opencv入门笔记之二 操作图像像素点
- openvc操作图片像素----之图像灰度处理
- OpenCV Core组件操作
- 图像的像素点操作
- opencv3/C++图像像素操作
- 撩汉就撩程序员
- VS中可执行文件不能单独运行
- java基础-BigInteger的使用
- Python服务端编程Gevent框架学习路线推荐
- 什么是Serverless无服务器架构?转自解道Jdon
- core组件之操作图像中的像素
- [spring源码学习]五-BeanPostProcessor的使用
- applicationContext.xml 文件头报错Referenced file contains errors
- 条款05:了解C++默默编写并调用哪些函数
- 浅谈商业银行绿色数据中心建设
- C++:求最大字串
- java集合之Map键值与Set、List、数组转换
- 三字母词及转义字符
- C++:队列的类实现