簡單圖像像素精確統計

今天寫程序中要知道圖像中某塊彩色圖像的像素分佈,於是很自然地想到寫個程序去統計一下,於是,想到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);
}


總結:

  1. 遇到問題追根求底,別放置一旁不管。
  2. 別被暫時的喜悅衝昏了頭腦。
  3. 問題總有解決的方法,走不通的時候換個角度試試。
  4. 快速排序還有鏈表沒有自己實現,偷懶了。找時間試試。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章