how to plot rgb color histogram of image with obje

2019-01-29 13:03发布

i want to show image RGB colour histogram in cocoa application. Please suggest possible way to do it with objective c or any third party library available to achieve this.

1条回答
唯我独甜
2楼-- · 2019-01-29 13:13

well this is a problem as RGB colors are 3D space so their histogram would lead to 4D plot which is something we do not really comprehend.

So the solution to this is to convert the 4D plot to 3D plot somehow. This can be done by sorting the colors by something that has some meaning. I will not speculate and describe what I am using. I use HSV color space and ignore the V value. This way I lose a lot of color shade info but it is still enough to describe colors for my purposes. This is how it looks like:

HSV histogram

You can also use more plots with different V to cover more colors. For more info see:

Anyway you can use any gradient sorting or any shape of your plot that is completely on you.

If you want pure RGB then you could adapt this and use RGB cube surface or map it on sphere and ignore the length from (0,0,0) (use unit vectors) something like this:

RGB histogram

So if you R,G,B are in <0,1> you convert that to <-1,+1> then compute the spherical coordinates (ignoring radius) and you got your 2 variables instead of 3 which you can use as a plot (either as 2D globe base or 3D sphere ...).

Here C++ code how to do this (made from the HSV histogram):

picture pic0,pic1,pic2,zed;

const int na=360,nb=180,nb2=nb>>1; // size of histogram table
int his[na][nb];
DWORD w;

int a,b,r,g,x,y,z,l,i,n;
double aa,bb,da,db,dx,dy,dz,rr;
color c;

pic2=pic0;                      // copy input image pic0 to pic2
for (a=0;a<na;a++)              // clear histogram
 for (b=0;b<nb;b++)
  his[a][b]=0;
for (y=0;y<pic2.ys;y++)         // compute it
 for (x=0;x<pic2.xs;x++)
    {
    c=pic2.p[y][x];
    r=c.db[picture::_r]-128;
    g=c.db[picture::_g]-128;
    b=c.db[picture::_b]-128;
    l=sqrt(r*r+g*g+b*b);        // convert RGB -> spherical a,b angles
    if (!l) { a=0; b=0; }
    else{
        a=double(double(na)*acos(double(b)/double(l))/(2.0*M_PI));
        if (!r) b=0; else b=double(double(nb)*atan(double(g)/double(r))/(M_PI)); b+=nb2;
        while (a<0) a+=na; while (a>=na) a-=na;
        if (b<0) b=0; if (b>=nb) b=nb-1;
        }
    his[a][b]++;            // update color usage count ...
    }
for (n=0,a=0;a<na;a++)      // max probability
 for (b=0;b<nb;b++)
  if (n<his[a][b]) n=his[a][b];

// draw the colored RGB sphere and histogram
zed =pic1; zed .clear(9999);    // zed buffer for 3D
           pic1.clear(0);       // image of histogram
da=2.0*M_PI/double(na);
db=M_PI/double(nb);
for (aa=0.0,a=0;a<na;a++,aa+=da)
 for (bb=-M_PI,b=0;b<nb;b++,bb+=db)
    {
    // normal
    dx=cos(bb)*cos(aa);
    dy=cos(bb)*sin(aa);
    dz=sin(bb);
    // color of surface (darker)
    rr=75.0;
    c.db[picture::_r]=double(rr*dx)+128;
    c.db[picture::_g]=double(rr*dy)+128;
    c.db[picture::_b]=double(rr*dz)+128;
    c.db[picture::_a]=0;
    // histogram center
    x=pic1.xs>>1;
    y=pic1.ys>>1;
    // surface position
    rr=64.0;
    z=rr;
    x+=double(rr*dx);
    y+=double(rr*dy);
    z+=double(rr*dz);
    if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; }
    // ignore lines if zero color count
    if (!his[a][b]) continue;
    // color of lines (bright)
    rr=125.0;
    c.db[picture::_r]=double(rr*dx)+128;
    c.db[picture::_g]=double(rr*dy)+128;
    c.db[picture::_b]=double(rr*dz)+128;
    c.db[picture::_a]=0;
    // line length
    l=(xs*his[a][b])/(n*3);
    for (double xx=x,yy=y,zz=z;l>=0;l--)
        {
        if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; }
        xx+=dx; yy+=dy; zz+=dz; x=xx; y=yy; z=zz;
        if (x<0) break; if (x>=xs) break;
        if (y<0) break; if (y>=ys) break;
        }
    }
  • input image is pic0, output image is pic1 (histogram graph)
  • pic2 is copy of pic0 (remnant of old code)
  • zed is the Zed buffer for 3D display avoiding Z sorting ...

I use my own picture class for images so some members are:


xs,ys size of image in pixels
p[y][x].dd is pixel at (x,y) position as 32 bit integer type
clear(color) - clears entire image
resize(xs,ys) - resizes image to new resolution

As the sphere is a 3D object you should add rotation to it so all the surface is visible in time (or rotate with mouse or whatever) ...

查看更多
登录 后发表回答