今天寫程序中要知道圖像中某塊彩色圖像的像素分佈,於是很自然地想到寫個程序去統計一下,於是,想到RGB每個分量都是0-255,於是非常自然地用了int count[256][256][256]……,很快編完,得意地編譯運行——直接報錯,棧溢出!!!不對,算了下需要的內存大小:內存要64M!(呃,昨天算錯了,以爲64G來着……我的是32位機)不知道怎麼回事,但是似乎是內存不夠了。現在還沒查出原因。我就考慮那麼就縮小內存吧。另外的原因就是考慮運行時間,如果算上所有的像素的話會非常慢。那麼,怎麼辦呢?
難不倒我,我想,因爲我統計的區域顏色比較集中,於是我可以想到可以先分別統計每個通道的量,然後過濾掉那些爲0的值,可以用幾個數組記錄每個非零的值以及它們對應的Index,然後重新組合成一個小型的RGB顏色空間,最好還能按統計值從大小輸出,於是還需要排序……好了,思路來了~
我用的是OpenCV,比較喜歡麼。
然後,文章權當是給大家參考,以及自己留念下,自己沒搞ACM,但是這種最實際的問題還是能自己解決的。
#include <cv.h>
#include <highgui.h>
#include <cxcore.h>
#define IMG_B(img,x,y) ((uchar*)(img->imageData + img->widthStep * (y)))[3 * (x)]
#define IMG_G(img,x,y) ((uchar*)(img->imageData + img->widthStep * (y)))[3 * (x) + 1]
#define IMG_R(img,x,y) ((uchar*)(img->imageData + img->widthStep * (y)))[3 * (x) + 2]
#define MAX_RANGE 12//這裏是我估計的大小
int main()
{
IplImage* src =cvLoadImage("test.bmp",1);
int B[256],G[256],R[256];//放每個通道分量的統計值
int tmpB[256],tmpG[256],tmpR[256];//放通道分量中非零的Index
memset(B,0,sizeof(B));
memset(G,0,sizeof(G));
memset(R,0,sizeof(R));
int tmpb[MAX_RANGE],tmpg[MAX_RANGE],tmpr[MAX_RANGE];//對應上面的Index,
//放Index對應的統計值,等於說實現了雙向查找
memset(tmpb,0,sizeof(tmpb));
memset(tmpg,0,sizeof(tmpg));
memset(tmpr,0,sizeof(tmpr));
for(int y = 0;y < src->height;y++)
{
for(int x = 0;x < src->width;x++)
{
B[IMG_B(src,x,y)]++;
G[IMG_G(src,x,y)]++;
R[IMG_R(src,x,y)]++;
}
}
int maxB = 0,minB = 255;
int maxG = 0,minG = 255;
int maxR = 0,minR = 255;
freopen("outcome.txt","w+",stdout);
int countB = 0;
for(int b = 0;b < 256;b++)
{
if(B[b]!= 0)
{
if(maxB < b)
maxB = b;
if(minB > b)
minB = b;
tmpb[countB] = b;
tmpB[b] = countB++;
//printf("B%d color:%d\n",b,B[b]);
}
}
int countG = 0;
for(int g = 0;g < 256;g++)
{
if(G[g] != 0)
{
if(maxG < g)
maxG = g;
if(minG > g)
minG = g;
tmpg[countG] = g;
tmpG[g] = countG++;
//printf("G:%d color:%d\n",g,G[g]);
}
}
int countR = 0;
for(int r = 0;r < 256;r++)
{
if(R[r] != 0)
{
if(maxR < r)
maxR = r;
if(minR > r)
minR = r;
tmpr[countR] = r;
tmpR[r] = countR++;
//printf("R:%d color:%d\n",r,R[r]);
}
}
//爲了排序,直接用一維數組,方便,而且多維似乎不能直接轉爲一維
int num = countB * countG * countR;
int* color = (int*)calloc(num,sizeof(int**));
for(int y = 0;y < src->height;y++)
for(int x = 0;x < src->width;x++)
{
//終於能統計了啊!!!
color[tmpB[IMG_B(src,x,y)] * countG * countR + tmpG[IMG_G(src,x,y)] * countR + tmpR[IMG_R(src,x,y)]]++;
}
int *p = color;
for(int i = 0;i < num;i++)//簡單排了下序
{
int max = p[i];
int imax = i;
for(int j = i + 1;j < num;j++)
{
if(max < p[j])
{
imax = j;
max = p[j];
}
}
if(imax != i)
{
int tmp = p[imax];
p[imax] = p[i];
p[i] = tmp;
}
}
//我姑且稱爲小型的RGB色彩空間
int index = 0;
for(int b = 0;b < countB;b++)
for(int g = 0;g < countG;g++)
for(int r = 0;r < countR;r++)
{
if(color[index] != 0)
printf("B:%3d G:%3d R:%3d ColorCount:%d\n",tmpb[b],tmpg[g],tmpr[r],color[index++]);
}
printf("maxB:%d maxG:%d maxR:%d\nminB:%d minG:%d minR:%d\n",maxB,maxG,maxR,minB,minG,minR);
free(color);
}
效果不錯,挺快的~
圖片在這裏
打完收功~
-----------------------------------------------------------------------------------------------------
以上是昨天的版本,發現了很多錯誤……
-----------------------------------------------------------------------------------------------------
好吧,我錯了,錯了很離譜,終於明白了,不是內存不夠,而是棧堆溢出,昨天的錯誤提示很明確的,我竟然沒好好理解。好吧,換calloc。還有就是排序丟失了RGB數據,得換個方法。於是,現在就出來一個正確無誤的版本:
#include <cv.h>
#include <highgui.h>
#include <cxcore.h>
#define IMG_B(img,x,y) ((uchar*)(img->imageData + img->widthStep * (y)))[3 * (x)]
#define IMG_G(img,x,y) ((uchar*)(img->imageData + img->widthStep * (y)))[3 * (x) + 1]
#define IMG_R(img,x,y) ((uchar*)(img->imageData + img->widthStep * (y)))[3 * (x) + 2]
#define MAX_RANGE 256
#define Count_Threshold 20//統計數據的閾值,不再以非零爲閾值了
struct Data//用結構體記錄RGB信息,也方便排序
{
uchar B,G,R,reserve;
int count;
};
static int compare(Data a,Data b)//用在sort中
{
return a.count > b.count;
}
int main()
{
IplImage* src =cvLoadImage("test.bmp",1);
//爲了排序,直接用一維數組,方便,而且多維似乎不能直接轉爲一維
int num = MAX_RANGE * MAX_RANGE * MAX_RANGE;
int* color = (int*)calloc(num,sizeof(int));
int maxB = 0,minB = 255;
int maxG = 0,minG = 255;
int maxR = 0,minR = 255;
freopen("outcome.txt","w+",stdout);
for(int y = 0;y < src->height;y++)
for(int x = 0;x < src->width;x++)
{
color[IMG_B(src,x,y) * MAX_RANGE * MAX_RANGE+ IMG_G(src,x,y) * MAX_RANGE + IMG_R(src,x,y)]++;
}
vector<Data> data;
int index = 0;
for(int b = 0;b < MAX_RANGE;b++)
for(int g = 0;g < MAX_RANGE;g++)
for(int r = 0;r < MAX_RANGE;r++)
{
if(color[index] >= Count_Threshold)
{
if(maxB < b)
maxB = b;
if(minB > b)
minB = b;
if(maxG < g)
maxG = g;
if(minG > g)
minG = g;
if(maxR < r)
maxR = r;
if(minR > r)
minR = r;
Data d;
d.B = b;
d.G = g;
d.R = r;
d.count = color[index];
data.push_back(d);
}
index++;
}
sort(data.begin(),data.end(),compare);//排序
for(int i = 0;i < data.size();i++)
printf("B:%3d G:%3d R:%3d ColorCount:%d\n",data[i].B,data[i].G,data[i].R,data[i].count);
printf("maxB:%d maxG:%d maxR:%d\nminB:%d minG:%d minR:%d\n",maxB,maxG,maxR,minB,minG,minR);
free(color);
}
- 遇到問題追根求底,別放置一旁不管。
- 別被暫時的喜悅衝昏了頭腦。
- 問題總有解決的方法,走不通的時候換個角度試試。
- 快速排序還有鏈表沒有自己實現,偷懶了。找時間試試。