• 从Opencv之图像直方图源码,探讨高性能计算设计思想


    前言

            纸上得来终觉浅,绝知此事要躬行。学会算法的理论很重要,但是把理论高效的实现也是需要一点点练习的。

            图像直方图的理论很简单,就是把一个图像的像素区间划分为几个子区间,然后统计图像中的像素包含在子区间内的个数。这里,我们可以很容易想到,图像每个像素之间对结果的影响是独立的,所以,代码实现时候可以考虑并行化设计。

    • 输入:image[h][w], bins, low, hign
    • 输出: hist[bins]

    Opencv的实现

    opencv的实现流程,以uint8编码的图像为例

    1,建立0-255到bins子区间的映射table。

    即table[256], index是0-255, table[index]是在histogram[bins]中的index。

     opencv建立table的接口函数

    1. static void calcHistLookupTables_8u( const Mat& hist,
    2. const SparseMat& shist,
    3. int dims, const float** ranges,
    4. const double* uniranges,
    5. bool uniform, bool issparse,
    6. vector<size_t>& _tab )

    关键逻辑代码:

    1. double t = bins/(high - low);
    2. double a = t
    3. double b = -t*low
    4. for (int j=low; j
    5. {
    6. int idx =cvFloor( j*a +b);
    7. table[j-low]=idx;
    8. }

    2,统计图像上0-255各像素值对应的个数。

    opencv每次统计四个相邻位置的像素,好像为利用了CPU流水线加速的原理,即同一指令,不同空间可以并行执行。
     

    opencv接口函数:

    1. static void calcHist_8u( vector& _ptrs,
    2. const vector<int>& _deltas,
    3. Size imsize, Mat& hist, int dims,
    4. const float** _ranges,
    5. const double* _uniranges, bool uniform )

    关键逻辑代码: 

    1. int matH[256] = { 0, };
    2. for( x = 0; x <= imsize.width - 4; x += 4 )
    3. {
    4. int t0 = p0[x], t1 = p0[x+1];
    5. matH[t0]++; matH[t1]++;
    6. t0 = p0[x+2]; t1 = p0[x+3];
    7. matH[t0]++; matH[t1]++;
    8. }
    9. p0 += x;
    10. for( ; x < imsize.width; x++, p0 += step)
    11. matH[*p0]++;

    3,合并matH和table,得到最终hist的输出。

    1. OUT_OF_RANGE =bins;
    2. uchar* H = hist.data;
    3. for(int i = 0; i < 256; i++ )
    4. {
    5. size_t hidx = tab[i];
    6. if( hidx < OUT_OF_RANGE )
    7. *(int*)(H + hidx) += matH[i];
    8. }

    整体流程关系:

    设计思路探讨

    1,为什么要拆分成三步完成呢?这样的时间复杂度=O(256+256+h*w)

    在遍历一次图像时候,为什么不同时完成hist的统计呢?可能opencv的映射查表用时更短,拆分步骤中1,2步可以同时完成。

    1. for i in range(Height):
    2.         for j in range(width):
    3.                 scale=bins/(high-low)
    4.                 index=image[i][i]*scale
    5.                 hist[index]+=1

    2,在实现遍历图像,每个点对结果的影响又是独立的,那么软件层面如何进行并行化加速?

    是不是能够分成多个线程读写image,在读取了image的像素值后,要对hist[pixes]或者matH[pixes]同一位置写数时候,加一个锁保护,即同一位置一次只能一个线程写数,只能串行,不能并行。

  • 相关阅读:
    正大数据周五新鲜报 做期货要关注哪块消息?
    Linux基本指令(一)
    Gitlab 仓库搭建(详细版)
    Java程序设计——PreparedStatement接口和CallableStatement接口(JDBC编程)
    愚人节礼物(C++)
    【异常报错】must call Vue.use(Vuex)
    网申线上测评,要不要找人代做在线测评?
    1985-2020年全国各省一二三产业就业人数/各省分产业就业人数数据(无缺失)
    java计算机毕业设计人口老龄化常态下的社区老年人管理与服务平台源程序+mysql+系统+lw文档+远程调试
    粽子食品小程序商城的作用是什么
  • 原文地址:https://blog.csdn.net/u010420283/article/details/128088391