Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 检查图像颜色的更快算法_C++_Visual C++ - Fatal编程技术网

C++ 检查图像颜色的更快算法

C++ 检查图像颜色的更快算法,c++,visual-c++,C++,Visual C++,假设给我一张2048x2048的图像,我想知道图像中存在的颜色总数,那么最快的算法是什么?我提出了两种算法,但它们都很慢 算法1: 比较当前像素和下一个像素,以及它们是否不同 检查包含所有检测到的颜色的临时变量,以查看颜色是否存在 如果不存在,则将其添加到数组(列表)并增加noOfColors 这个算法有效,但速度很慢。对于1600x1200像素的图像,大约需要3秒 算法2: 将每个像素与所有其他像素一起检查,记录颜色出现次数并增加计数的明显方法。这是非常非常慢,几乎像一个挂起的应用程序。那

假设给我一张2048x2048的图像,我想知道图像中存在的颜色总数,那么最快的算法是什么?我提出了两种算法,但它们都很慢

算法1:

  • 比较当前像素和下一个像素,以及它们是否不同
  • 检查包含所有检测到的颜色的临时变量,以查看颜色是否存在
  • 如果不存在,则将其添加到数组(列表)并增加noOfColors
这个算法有效,但速度很慢。对于1600x1200像素的图像,大约需要3秒

算法2:
将每个像素与所有其他像素一起检查,记录颜色出现次数并增加计数的明显方法。这是非常非常慢,几乎像一个挂起的应用程序。那么有没有更好的方法?我需要所有的像素信息。

你可以使用(或),只需在像素上做一个循环,将颜色添加到集合中。然后颜色的数量就是集合的大小。

好的,这适合于并行化。将图像分割为几个部分,并在单独的任务中为每个部分执行算法。为了避免同步,每种颜色都应该有自己的存储空间。所有任务完成后,您将聚合结果。

这里唯一可行的算法是建立一种图像颜色的直方图。在你的例子中唯一的不同是,你不需要计算每种颜色的总体,你只需要知道它是否为零

根据您使用的颜色空间的不同,您可以使用
std::set
标记现有颜色(正如Joachim Pileborg所建议的),或者只使用类似
std::bitset
的东西,这显然更快。这取决于颜色空间中存在多少不同的颜色

此外,正如Marius Bancila所指出的,这个过程非常适合并行化。计算图像部分的直方图数据,然后将其合并。当然,图像分割应该基于其内存分区,而不是几何特性。简单地说,垂直分割图像(按扫描线的批次),而不是水平分割


而且,如果可能的话,您应该使用一些低级库/代码来运行像素,或者尝试编写自己的。至少你必须获取一个指向扫描线的指针,并在扫描线的像素上批量运行,而不是对每个像素执行类似于GetPixel的操作。

这里的要点是,图像作为2D颜色数组的理想表示方式并不是图像存储在内存中的方式(颜色组件可以排列在“平面”中,可能有“填充”等。因此使用类似于
GetPixel
的函数获取像素可能需要时间

因此,如果图像不是“矢量绘制”的结果,那么这个问题甚至可能毫无意义:想象一张照片:在附近的两个“绿色”之间,你会发现所有的绿色阴影,因此颜色——在这种情况下——不再是图像本身编码所支持的颜色(2^24,或256,或16或……),因此,除非你对颜色分布感兴趣(它们的使用方式有多不同),否则仅仅计算它们是没有意义的

解决方法可以是:

  • 创建具有“单平面格式”像素的内存位图
  • 使用BitBlt或类似工具将图像Blit到位图中(这让操作系统能够生成像素) 从GPU转换(如果有)
  • 获取位图位(这让您 访问存储的值)
  • 玩你的“计数算法”(随便什么) 它是在这些价值观之上
  • 请注意,如果您已经知道图像已经是平面格式,则可以避免步骤1和2

    如果您有一个多核系统,步骤4也可以分配给不同的线程,图像的每个工作部分。

    您可以使用它来设置单个位并具有一个功能

    每种颜色有一个位,每个RGB有256个值,即256*256*256位(16777216种颜色)。位集将每8位使用一个字节,因此它将使用2MB

    使用像素颜色作为
    位集的索引

    bitset<256*256*256> colours;
    
    for(int pixel: pixels) {
        colours[pixel] = true;
    }
    
    colours.count();
    
    位集颜色;
    用于(整数像素:像素){
    颜色[像素]=真;
    }
    颜色。计数();
    

    这具有线性复杂性。

    DRAM非常便宜。使用蛮力。填写选项卡,计数

    在3.0GHz的core2duo上:

    4096x4096 32位rgb为0.35秒

    在一些琐碎的并行化之后0.20秒(我对omp一无所知)

    但是,如果要使用64位rgb(一个通道=16位),则是另一个问题(内存不足)。 您可能需要一个好的哈希表函数。 使用随机像素,相同大小需要10秒

    备注:在0.15秒时,std::bitset解决方案的速度更快(它变得更慢,只是简单的并行化!)

    解决方案,c++11

        #include <vector>
    #include <random>
    #include <iostream>
    #include <boost/chrono.hpp>
    
    #define  _16M 256*256*256
    
    typedef union {
        struct { unsigned char r,g,b,n ; } r_g_b_n ;
        unsigned char rgb[4] ;
        unsigned i_rgb;
    } RGB ;
    
    RGB make_RGB(unsigned char r, unsigned char g , unsigned char b) {
        RGB res; 
        res.r_g_b_n.r = r; 
        res.r_g_b_n.g = g;
        res.r_g_b_n.b = b;
        res.r_g_b_n.n = 0;
        return res;
    }
    
    static_assert(sizeof(RGB)==4,"bad RGB size not 4");
    static_assert(sizeof(unsigned)==4,"bad i_RGB size not 4");
    
    struct Image 
    { 
      Image (unsigned M, unsigned N) : M_(M) , N_(N) , v_(M*N) {}
      const RGB* tab() const {return & v_[0] ; }
      RGB* tab() {return & v_[0] ; }
      unsigned M_ , N_;
      std::vector<RGB> v_;
    };
    
    void FillRandom(Image & im) {
        std::uniform_int_distribution<unsigned> rnd(0,_16M-1);
        std::mt19937 rng;
        const int N = im.M_ * im.N_;
        RGB* tab = im.tab();
        for (int i=0; i<N; i++) {
            unsigned r = rnd(rng) ;
            *tab++ = make_RGB(  (r & 0xFF) , (r>>8 & 0xFF), (r>>16 & 0xFF) ) ;
        }
    }
    
    size_t Count(const Image & im) {
    const int N = im.M_ * im.N_;
    std::vector<char> count(_16M,0);
    const RGB* tab = im.tab();
    #pragma omp parallel 
    {
    #pragma omp for 
    for (int i=0; i<N; i++) {
        count[ tab->i_rgb ] = 1 ;
        tab++;
        }
    }
    size_t nColors = 0 ;
    #pragma omp parallel 
    {
    #pragma omp for 
    for (int i = 0 ; i<_16M; i++) nColors += count[i];
    }
    return nColors;
    }
    
    int main() {
        Image im(4096,4096);
        FillRandom(im);
        typedef boost::chrono::high_resolution_clock hrc;
        auto start = hrc::now();
    
        std::cout << " # colors " << Count(im) << std::endl ; 
    
        boost::chrono::duration<double> sec  = hrc::now() - start;
        std::cout << " took " << sec.count() << " seconds\n";
        return 0;
    }
    
    #包括
    #包括
    #包括
    #包括
    #定义_16m256*256*256
    typedef联合{
    结构{无符号字符r,g,b,n;}r_g_b_n;
    无符号字符rgb[4];
    未签名的i_rgb;
    }RGB;
    RGB make_RGB(无符号字符r、无符号字符g、无符号字符b){
    RGB res;
    res.r_g_b_n.r=r;
    res.r_g_b_n.g=g;
    res.r_g_b_n.b=b;
    res.r_g_b_n.n=0;
    返回res;
    }
    静态断言(sizeof(RGB)==4,“错误的RGB大小不是4”);
    static_assert(sizeof(unsigned)=4,“坏i_RGB大小不是4”);
    结构映像
    { 
    图像(无符号M,无符号N):M(M),N(N),v(M*N){
    常量RGB*tab()常量{return&v_u0];}
    RGB*制表符(){return&v_[0];}
    无符号M_uu,N_u;
    std::向量v_;
    };
    无效填充随机(图像和im){
    标准:均匀分布rnd(0,_16M-1);
    标准:mt19937 rng;
    常数int N=im.M_*im.N;
    RGB*tab=im.tab();
    对于(inti=0;i>8&0xFF),(r>>16&0xFF));
    }
    }
    大小\u t计数(常量图像和im){
    常数int N=im.M_*im.N;
    标准:病媒计数(_16M,0);
    常量RGB*tab=im.tab();
    #pragma-omp并行
    
    char * creatematcharray(struct rgb_color *palette, int palettesize)
        {
          int rval=16, gval=16, bval=16, len, r, g, b;
          char *taken, *match, *same;
          int i, set, sqstep, tp, maxtp, *entryr, *entryg, *entryb;
          char *table;
    
          len=rval*gval*bval;
    
          // Prepare table buffers:
          size_t size_of_table = len*sizeof(char);
          table=(char *)malloc(size_of_table);
          if (table==nullptr) return nullptr;
    
          // Select colors to use for fill:
          set=0;
          size_t size_of_taken = (palettesize * sizeof(int) * 3) +
              (palettesize*sizeof(char)) + (len * sizeof(char));
          taken=(char *)malloc(size_of_taken);
          same=taken + (len * sizeof(char));
          entryr=(int*)(same + (palettesize * sizeof(char)));
          entryg=entryr + palettesize;
          entryb=entryg + palettesize;
          if (taken==nullptr)
          {
            free((void *)table);
            return nullptr;
          }
          std::memset((void *)taken, 0, len * sizeof(char));
        //  std::cout << "sizes: " << size_of_table << " " << size_of_taken << std::endl;
    
          match=table;
          for (i=0; i<palettesize; i++)
          {
            same[i]=0;
            // Compute 3d-table coordinates of palette rgb color:
            r=palette[i].r&0x0f, g=palette[i].g&0x0f, b=palette[i].b&0x0f;
            // Put color in position:
            if (taken[b*rval*gval+g*rval+r]==0) set++;
            else same[match[b*rval*gval+g*rval+r]]=1;
            match[b*rval*gval+g*rval+r]=i;
            taken[b*rval*gval+g*rval+r]=1;
            entryr[i]=r; entryg[i]=g; entryb[i]=b;
          }
    
          // @@@ Fill match_array by steps: @@@
          for (set=len-set, sqstep=1; set>0; sqstep++)
          {
            for (i=0; i<palettesize && set>0; i++)
              if (same[i]==0)
              {
                // Fill all six sides of incremented cube (by pairs, 3 loops):
                for (b=entryb[i]-sqstep; b<=entryb[i]+sqstep; b+=sqstep*2)
                  if (b>=0 && b<bval)
                    for (r=entryr[i]-sqstep; r<=entryr[i]+sqstep; r++)
                      if (r>=0 && r<rval)
                      { // Draw one 3d line:
                        tp=b*rval*gval+(entryg[i]-sqstep)*rval+r;
                        maxtp=b*rval*gval+(entryg[i]+sqstep)*rval+r;
                        if (tp<b*rval*gval+0*rval+r)
                          tp=b*rval*gval+0*rval+r;
                        if (maxtp>b*rval*gval+(gval-1)*rval+r)
                          maxtp=b*rval*gval+(gval-1)*rval+r;
                        for (; tp<=maxtp; tp+=rval)
                          if (!taken[tp])
                            taken[tp]=1, match[tp]=i, set--;
                      }
                for (g=entryg[i]-sqstep; g<=entryg[i]+sqstep; g+=sqstep*2)
                  if (g>=0 && g<gval)
                    for (b=entryb[i]-sqstep; b<=entryb[i]+sqstep; b++)
                      if (b>=0 && b<bval)
                      { // Draw one 3d line:
                        tp=b*rval*gval+g*rval+(entryr[i]-sqstep);
                        maxtp=b*rval*gval+g*rval+(entryr[i]+sqstep);
                        if (tp<b*rval*gval+g*rval+0)
                          tp=b*rval*gval+g*rval+0;
                        if (maxtp>b*rval*gval+g*rval+(rval-1))
                          maxtp=b*rval*gval+g*rval+(rval-1);
                        for (; tp<=maxtp; tp++)
                          if (!taken[tp])
                            taken[tp]=1, match[tp]=i, set--;
                      }
                for (r=entryr[i]-sqstep; r<=entryr[i]+sqstep; r+=sqstep*2)
                  if (r>=0 && r<rval)
                    for (g=entryg[i]-sqstep; g<=entryg[i]+sqstep; g++)
                      if (g>=0 && g<gval)
                      { // Draw one 3d line:
                        tp=(entryb[i]-sqstep)*rval*gval+g*rval+r;
                        maxtp=(entryb[i]+sqstep)*rval*gval+g*rval+r;
                        if (tp<0*rval*gval+g*rval+r)
                          tp=0*rval*gval+g*rval+r;
                        if (maxtp>(bval-1)*rval*gval+g*rval+r)
                          maxtp=(bval-1)*rval*gval+g*rval+r;
                        for (; tp<=maxtp; tp+=rval*gval)
                          if (!taken[tp])
                            taken[tp]=1, match[tp]=i, set--;
                      }
              }
          }
          free((void *)taken);`enter code here`
          return table;
        }
    
    #define USEHASH 1
    #ifdef USEHASH
    #include <unordered_map>
    #endif
    
    size = im->xw * im->yw;
    #ifdef USEHASH
    // unordered_map is about twice as fast as map on my mac with qt5
    // --------------------------------------------------------------
    #include <unordered_map>
        std::unordered_map<qint64, unsigned char> colors;
        colors.reserve(size); // pre-allocate the hash space
    #else
        std::map<qint64, unsigned char> colors;
    #endif
    
    for (i=0; i<size; i++)
    {
        pel = BUILDPEL(i); // macro just shovels 0RGB into 64 bit pel from im
                           // You'd do the same for your image structure
                           // in whatever way is fastest for you
        colors[pel] = 1;
    }
    cc = colors.size();
    // time here: 14 secs for map, 7 secs for unordered_map with
    // 12,106,244 pixels containing 11,857,131 colors on 12/24 core,
    // 3 GHz, 64GB machine.