Как построить RGB цветную гистограмму изображения с целью

Я хочу показать изображение RGB цветовой гистограммы в приложении какао. Пожалуйста, предложите возможный способ сделать это с целью c или любой сторонней библиотекой, доступной для достижения этой цели.

1 ответ

Решение

Что ж, это проблема, так как цвета RGB являются трехмерным пространством, поэтому их гистограмма приведет к 4- мерному графику, который мы на самом деле не понимаем.

Поэтому решение этой проблемы заключается в том, чтобы как-то преобразовать 4D- график в 3D- график. Это можно сделать, отсортировав цвета по значению. Я не буду спекулировать и описывать то, что я использую. Я использую цветовое пространство HSV и игнорирую значение V. Таким образом, я теряю много информации о цветовых оттенках, но этого все же достаточно, чтобы описать цвета для моих целей. Вот как это выглядит:

Гистограмма ВПГ

Вы также можете использовать больше участков с разными V чтобы покрыть больше цветов. Для получения дополнительной информации см.:

В любом случае вы можете использовать любую градиентную сортировку или любую форму вашего графика, которая полностью на вас.

Если вы хотите чистый RGB, вы можете адаптировать его и использовать поверхность RGB- куба или отобразить его на сфере и игнорировать длину от (0,0,0) (используйте единичные векторы) примерно так:

Гистограмма RGB

Так что если вы R,G,B находятся в <0,1> вы конвертируете это в <-1,+1> затем вычислите сферические координаты (игнорируя радиус), и вы получите 2 переменные вместо 3, которые вы можете использовать в качестве графика (либо в качестве 2D- основы глобуса, либо 3D- сферы...).

Вот код C++, как это сделать (сделан из гистограммы HSV):

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;
        }
    }
  • входное изображение pic0, выходное изображение pic1 (график гистограммы)
  • pic2 это копия pic0 (остаток старого кода)
  • zed это буфер Zed для отображения 3D, избегающий сортировки по Z...

Я использую свой собственный класс изображений для изображений, поэтому некоторые участники:


xs,ys размер изображения в пикселях
p[y][x].dd является пикселем в положении (x,y) как 32-битный целочисленный тип
clear(color) - очищает все изображение
resize(xs,ys) - изменяет размер изображения до нового разрешения

Поскольку сфера является трехмерным объектом, вы должны добавить к нему вращение, чтобы вся поверхность была видна во времени (или вращаться с помощью мыши или чего-либо еще) ...

Другие вопросы по тегам