如何使用 objective c 绘制图像的 rgb 颜色直方图
how to plot rgb color histogram of image with objective c
我想在 cocoa 应用程序中显示图像 RGB 颜色直方图。请建议使用 objective c 或任何可用的第三方库来实现此目的的可能方法。
这是个问题,因为 RGB 颜色是 3D space 所以它们的直方图会导致 4D 情节是我们没有真正理解的东西。
所以解决这个问题的方法是将 4D 图以某种方式转换为 3D 图。这可以通过按具有某种意义的事物对颜色进行排序来完成。我不会推测和描述我使用的是什么。我使用 HSV 颜色 space 并忽略 V 值。这样我丢失了很多颜色阴影信息,但它仍然足以描述我的目的的颜色。这是它的样子:
您还可以使用不同 V
的更多图来覆盖更多颜色。有关详细信息,请参阅:
无论如何,您可以使用任何梯度排序或完全由您决定的任何图形形状。
如果你想要纯 RGB 那么你可以调整它并使用 RGB 立方体表面或将其映射到球体上并忽略来自(0,0,0)
(使用单位向量)像这样:
因此,如果您 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
是用于 3D 显示的 Zed 缓冲区,避免 Z 排序 ...
我使用自己的图片 class 作为图片,所以一些成员是:
xs,ys
图像大小(以像素为单位)
p[y][x].dd
是 (x,y) 位置的像素,为 32 位整数类型
clear(color)
- 清除整个图像
resize(xs,ys)
- 将图像调整为新分辨率
由于球体是 3D 对象,您应该为其添加旋转,以便所有表面都及时可见(或用鼠标或其他方式旋转)...
我想在 cocoa 应用程序中显示图像 RGB 颜色直方图。请建议使用 objective c 或任何可用的第三方库来实现此目的的可能方法。
这是个问题,因为 RGB 颜色是 3D space 所以它们的直方图会导致 4D 情节是我们没有真正理解的东西。
所以解决这个问题的方法是将 4D 图以某种方式转换为 3D 图。这可以通过按具有某种意义的事物对颜色进行排序来完成。我不会推测和描述我使用的是什么。我使用 HSV 颜色 space 并忽略 V 值。这样我丢失了很多颜色阴影信息,但它仍然足以描述我的目的的颜色。这是它的样子:
您还可以使用不同 V
的更多图来覆盖更多颜色。有关详细信息,请参阅:
无论如何,您可以使用任何梯度排序或完全由您决定的任何图形形状。
如果你想要纯 RGB 那么你可以调整它并使用 RGB 立方体表面或将其映射到球体上并忽略来自(0,0,0)
(使用单位向量)像这样:
因此,如果您 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
是用于 3D 显示的 Zed 缓冲区,避免 Z 排序 ...
我使用自己的图片 class 作为图片,所以一些成员是:
xs,ys
图像大小(以像素为单位)
p[y][x].dd
是 (x,y) 位置的像素,为 32 位整数类型
clear(color)
- 清除整个图像
resize(xs,ys)
- 将图像调整为新分辨率
由于球体是 3D 对象,您应该为其添加旋转,以便所有表面都及时可见(或用鼠标或其他方式旋转)...