0

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.

Sansnagar
  • 124
  • 6
  • When I read your question the only proper answer would be "Yes". Unfortunately that is too short to be entered. Asking for library recommendations is off-topic. Any image processing library will work. It will either provide you the tool out of the box or the means to implement it yourself. It is rather simple. Just google. – Piglet Mar 28 '17 at 07:42
  • sorry, i have modified the question now. Do u know possible way to do it. – Sansnagar Mar 28 '17 at 10:52
  • You just reworded a few things. That does not improve your question at all. Asking for libraries is off-topic. You should use a websearch like google to find an image processing library. I am sure "image-processing cocoa" or "image-processing objective c" will yield plenty of results. You either need a library that provides you that histogram functionality or at least something that allows you to read images and access their pixel data. Implementing everything yourself is not very effective. But once you have at least pixel data it's a matter of minutes until you have histograms. – Piglet Mar 28 '17 at 11:16

1 Answers1

2

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) ...

Community
  • 1
  • 1
Spektre
  • 49,595
  • 11
  • 110
  • 380