查找表
颜色缩减法:如果矩阵元素存储的是单通道像素,使用C或C++的无符号字符类型,那么像素可有256个不同值。
但若是三通道图像,这种存储格式的颜色数就太多了(确切地说,有一千六百多万种)。用如此之多的颜色可能
会对我们的算法性能造成严重影响。其实有时候,仅用这些颜色的一小部分,就足以达到同样效果。
这种情况下,一种常用的做法是,颜色空间缩减,将现有颜色空间值除以某个值,以获得较少的颜色数。
Inew=(Iold/10)*10
简单的颜色空间缩减可由下面两部分组成:1.遍历图像矩阵的每一个像素 2.对像素应用上述公式。 在这个过程中
用到了乘法和除法,而这两种运算又特别费时,所以应尽可能用代价较低的加减或赋值替代。这时,可以预先计
算出所有可能的值,然后需要这些值的时候,利用查找表赋值即可。查找表是一维或多维数组,存储了不同输入
值所对应的输出值,其优势在于只需读取、无需计算。
void CreateLookupTable(uchar* table, uchar divideWith) { for (int i = 0; i < 256; i++) { table[i] = (i / divideWith)*divideWith; } }
图像扫描
1.Efficient Way
Mat& ScanImageAndReduceC(Mat& I, const uchar* table) { //检测只能为uchar类型 CV_Assert(I.depth() != sizeof(uchar)); int channels = I.channels(); int nRows = I.rows*channels; int nCols = I.cols; if (I.isContinuous()) { nCols*= nRows; nRows = 1; } int i, j; uchar *p; for (i = 0; i < nRows; ++i) { p = I.ptr<uchar>(i); for (j = 0; j < nCols; ++j) { p[j] = table[p[j]]; } } return I; }
这里p是图像矩阵的第i行指针,p[j]即是图像的第i行第j列的像素值。获取每一行开始处指针,然后遍历至行末,
如果矩阵是连续存储的,只需请求一次指针然后一路遍历下去。
2.The Iterator Method
获取图像的Begin和End然后增加迭代,直至从begin到end。
Mat& ScanImageAndReduceIterator(Mat& I, const uchar* table) { CV_Assert(I.depth() != sizeof(uchar)); const int channels = I.channels(); switch (channels) { case 1: { MatIterator_<uchar>it, end; for (it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it) { *it = table[*it]; } break; } case 3: { MatIterator_<Vec3b>it, end; for (it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; ++it) { (*it)[0] = table[(*it)[0]]; (*it)[1] = table[(*it)[1]]; (*it)[2] = table[(*it)[2]]; } } } return I; }
对于彩色图像中的一行,每一列中有三个uchar元素,这可以认为是一个小的包含uchar元素的vector。在openCV中用Vec3b来命名。
如果要访问第n的子列,只需用简单的[]操作就可以。需要指出的是,OpenCV的迭代在扫描过一行中所有列后会自动跳至下一行,所以
说如果在彩色图像中如果只使用一个简单的 uchar 而不是 Vec3b 迭代的话就只能获得蓝色通道(B)里的值。
3.通过相关返回值的On-the-fly地址计算
这个方法本身用户获取或更改图像中的随机元素。它的基本用途是要确定你试图访问的元素的所在行数与列数。需要自己制定好所要查
找的元素的数据类型。