how to plot histogram of image using visual studio

metamofia's Avatar
Go4Expert Member
hi guys im on a project to come up with a histogram equalization but right now i need to display the histogram for now. so far everything i did was okay to me except that my histogram is not a proper one. here is my code below:

Code:
 
//**************************************************************************************//
void CLEO_MedivisionView::OnUpdateToolsHistogram(CCmdUI *pCmdUI)
{
// TODO: Add your command update UI handler code here

if (fileopen)
{
pCmdUI->Enable(true);
}
else
{
pCmdUI->Enable(false);
}
}
void CLEO_MedivisionView::OnToolsHistogram()
{
// TODO: Add your command handler code here
int x_tick, y_tick;
int j;
int a_loop, b_loop;
int k, t, f, i;
int x;
int q;
unsigned int intMFC;
unsigned int intMFC1;
unsigned int intMFC2;
unsigned short array1[256];
char c[10];
char p[10];
char l[10];
CString MFCString;

pDC = GetDC(); //OnDraw member function
hdc = pDC->GetSafeHdc();
CPen aPen, greenPen;
aPen.CreatePen(PS_SOLID, 2, RGB(255, 225, 225));
greenPen.CreatePen(PS_SOLID, 1, RGB(124, 252, 0));
CPen* pOldPen = pDC->SelectObject(&aPen);
 
pDC->MoveTo(600,400); //drawing of x-axis
pDC->LineTo(920,400);
pDC->MoveTo(920,400);
pDC->LineTo(915,405);
pDC->MoveTo(920,400);
pDC->LineTo(915,395); //drawing of x-axis

x_tick = 600; //declaring constants
y_tick = 400;
for(j=1; j<=10; j++) //control the loop so that it draws ticks every 30 pixels
{
pDC->MoveTo(x_tick+(j*30),y_tick-5); 
pDC->LineTo(x_tick+(j*30),y_tick+5); 
}
pDC->MoveTo(600,400); //drawing of y-axis
pDC->LineTo(600,80);
pDC->MoveTo(600,80);
pDC->LineTo(605,85);
pDC->MoveTo(600,80);
pDC->LineTo(595,85); //drawing of y-axis
for(t=1; t<=10; t++) //control the loop so that it draws ticks every 30 pixels
{
pDC->MoveTo(x_tick-5,y_tick-(t*30)); 
pDC->LineTo(x_tick+5,y_tick-(t*30));
}
intensity= "Intensity"; //labelling of x-axis
SetBkColor(hdc, RGB(0, 0, 0));
SetTextColor(hdc, RGB(255, 255 ,255 ));
TextOut(hdc, 930, 390, LPCTSTR(intensity), 9);
pixels = "Pixels"; //labelling of y-axis
SetTextColor(hdc, RGB(255, 255 ,255 ));
TextOut(hdc, 580, 55, LPCTSTR(pixels), 6); 
numeric = "0"; //number zero (universal)
SetTextColor(hdc, RGB(95, 158, 160));
TextOut(hdc, 585, 400, LPCTSTR(numeric),1);
intMFC = 0; //declaring constants
a_loop = 595;
for(k=1; k<=5; k++) //for every two ticks, draw legend of +52 each time it loops
{ 
intMFC = intMFC+51;
itoa(intMFC,c,10);
CString MFCString;
MFCString = c;
if(intMFC<100) //if number is XX then just show 2 digits
{
test = c;
SetTextColor(hdc, RGB(95, 158 ,160));
TextOut(hdc, a_loop+(k*60), 405, LPCTSTR(test), 2);
}
else if(intMFC>=100) //if number is XXX then show 3 digits
{
test = c;
SetTextColor(hdc, RGB(95, 158, 160));
TextOut(hdc, a_loop+(k*60), 405, LPCTSTR(test), 3);
}
}
intMFC1 = 0; //declaring of constants
intMFC2 = 0;
b_loop = 392;


//'for' loop couting from 0 to 255 which simply zeros out each element in array1 to prepare the array to do the count of the bytes in the image
for (i=0;i<256;i++) 
{
array1[i]=0;
}
//'for' loop to loop through the bytes of the image
for (i=0; i<262144; i++)
{ 
array1[image[i]]++;
}
for (i=0; i<65536; i++)
{
array1[image256[i]]++;
}

//find the array location containing most value
int highest=0; 
for (int i=0; i<256; i++) 
{
if (array1[i] > highest)
highest = array1[i];
}
if (no_of_rows == 256 && no_of_cols == 256) // initiate if image its by 256*256
{
for(f=1; f<=5; f++) // for 5-ticks axis
{ 
intMFC1 = (((highest+99)/100)*100)/5*f; // calculation
itoa(intMFC1,p,10); 
CString MFCString;
MFCString = p;
if(intMFC1<10000)
{
test1=p;
SetTextColor(hdc, RGB(95, 158 ,160));
TextOut(hdc, 540, b_loop-(f*60), LPCTSTR(test1), 4);
} 
else if(intMFC1>=10000)
{ 
test1 = p;
SetTextColor(hdc, RGB(95, 158 ,160));
TextOut(hdc, 540, b_loop-(f*60), LPCTSTR(test1), 5);
}
}
}
else if (no_of_rows == 512 && no_of_cols == 512) // if image is 512*512 run this
{
for(q=1; q<=5; q++) // for 5-ticks axis 
{ 
intMFC2 = (((highest+99)/100)*100)/5*q; // calculation
itoa(intMFC2,l,10); 

MFCString = l; 
if(intMFC2<10000) 

{
test2 = l;
SetTextColor(hdc, RGB(95, 158 ,160));
TextOut(hdc, 540, b_loop-(q*60), LPCTSTR(test2), 4); 
}
else if(intMFC2>=10000) //if digit is more or equal to 100000, do this
{
test2 = l;
SetTextColor(hdc, RGB(95, 158, 160));
TextOut(hdc, 540, b_loop-(q*60), LPCTSTR(test2),5);
}
}
}

//green colour pen for histogram lines
CPen* gOldPen = pDC->SelectObject(&greenPen);
//starting of histogram drawing (intensity vs pixel value)
pDC->MoveTo(600, 398);
for (i=1; i<256; i++)

{ 
pDC->MoveTo(600+i, 398);
pDC->LineTo(600+i, (398-(array1[i]*398/highest)));
}
}
when i run this program, the histogram was displayed in a distorted manner. i will post a screenshot attached to this post. so right now, as instructed by my supervisor, i need to display the histogram properly before i can do anything else. as you will see, the y-axis, or the pixel number axis is scaled to show only the total number of pixels of the intensity value(ie 0-255). for example array1[200]= 43456. so this intensity has the msot pixel value so my y-axis will be in range from 0-43500. its already scaled. so if possible pls help me on the plotting of the histogram. thanks alot.
Attached Images
File Type: jpg clip_image001.jpg (27.3 KB, 7 views)

Last edited by metamofia; 9Oct2009 at 12:24..
0
xpi0t0s's Avatar, Join Date: Aug 2004
Mentor
What should it look like?

As previously suggested, if you output the values used in drawing the histogram to a file, can you see from the resulting numbers what is wrong?

Looking at the image, it's compressed so I can't make it out clearly, but you do seem to have a large number of faint pixels and a smaller number of brighter ones, and the resulting histogram does seem to fit the image. Have you tried pasting a screen shot into an application that can do histograms to see what it makes of the image? For example Paint Shop Pro can do histograms, and the one it plots for the image looks very similar to the one you've already plotted.

So are you sure it's wrong? If so can you describe exactly how it's wrong?
0
metamofia's Avatar
Go4Expert Member
Hi, well is it possible for u to zoom the thumbnail i attached earlier? well seemingly as you can roughly see: my x-axis starts from 0-255 and its 320 pixels long. so by right my histogram should stretch all the way to the ticker 255 but currently it just occupy a small portion for whatever reasons. and yes, i did check the values in array1[] and seems reasonable cause, ie array1[0] has 45000+ pixels since most of the image is black. and the gray values are equally distributed. so the problem now lies on the plotting of histogram i think. and if you can roughly see my y-axis, its program so that the peak of it just show the most NUMBER OF PIXELS FOR A PARTICULAR INTENSITY. for example since my black has 45000 pixels, then the y-axis range is from 0-45000. so also in this case my histogram should stretch to the y axis. but unfortunately its not. any ideas?

PS: i dont have the application with me and the only few things available in my project PC is Visual Studio C++. Not even Paint software. Thanks for the help.

Last edited by metamofia; 12Oct2009 at 08:16..
0
xpi0t0s's Avatar, Join Date: Aug 2004
Mentor
Have another look at the for loop and see if you can see any reason it might not plot the array1[0] line (hint: there is a reason, so you just need to look at it until you see it, and NO I'm not going to give it away so don't ask -- finding bugs is what programming is all about. I'm already giving you a massive hint just by telling you where to look. If you don't want to learn how to find bugs then you're in the wrong job, probably 90% of programming is bug-fixing.)

Attached is what Paint Shop Pro thinks your histogram should look like. It's very similar to what you've already got. Why do you think your histogram should look any different? If what you want is for the curve to be scaled over the width, then you will need to perform similar scaling for what you did with the y-axis, i.e. work out the range of data you want to display then scale that to fit the available screen.
Attached Images
File Type: jpg Image4.jpg (117.2 KB, 6 views)
0
metamofia's Avatar
Go4Expert Member
Okay thanks i think i know where i went bonkers. my condition was set to i=1 onwards. i have ammended it and now the array1[0] line is there and its shot to infinity. i will attached the thumbnail below.

okay what im trying to say earlier was: my y-axis is coded in a way that the Max value of the axis = the total number of pixel that has the most repetition of the same intensity value. in referrence to the thumbnail, the the total number of pixel that has the most repetition is the black intensity and its 43542.

so i came up with this algorithm:
Code:
 
int highest=0; 
for (int i=0; i<256; i++) 
{
if (array1[i] > highest)
highest = array1[i];
}

intMFC2 = (((highest+99)/100)*100)/5*q
this equation is use to round up to the nearest 100 which in this case will be 43600 and its correct. so as ur advised, the histogram need not to be stretched along the x-axis but there is a problem along the y-axis. any hints or help? thanks alot.
Attached Images
File Type: jpg clip_image005.jpg (30.5 KB, 5 views)

Last edited by metamofia; 12Oct2009 at 14:03..
0
xpi0t0s's Avatar, Join Date: Aug 2004
Mentor
What point on the screen do you want the higher end of the array1[0] line to end at?
What is the value in array1[0]?
Is it equal to highest?
What will be the result of the calculation 398-(array1[0]*398/highest)?
0
metamofia's Avatar
Go4Expert Member
What point as in the EXACT (x,y) pixel values on the screen?

For the image in the thumbnail, the value of array1[0] is 43542 hence, during the plotting of the legend on the marker on y axis, the max value is rounded up to 43600 so i want the line to end just slightly below the 43600 marker just to show the difference.

As for this line of equation >> 398-(array1[0]*398/highest),
im not sure the numeric result and i was just playing around with the values within the bracket since the '398-' is used for normalization on the histogram. frim what i know so far (not much actually), i need to do a scaling or proportionating. but im not too sure how to kickstart it.
0
xpi0t0s's Avatar, Join Date: Aug 2004
Mentor
> What point as in the EXACT (x,y) pixel values on the screen?

Yes. It seems to me that you need to know this to work out an equation to return this result from the variables and constants you have.

> im not sure the numeric result

OK, so as previously advised, write this stuff out to a file. Then you know for certain what numbers it's using. It would also help you to write out the contents of array[] to the file, I think.

None of the questions I asked are without a point. So for your own benefit you should try to answer them. If you don't then it also makes me wonder what the point of replying further to this thread is.
0
metamofia's Avatar
Go4Expert Member
Okay got it. Well it has to be (600,100) = the rounded up value which is 43600
So for this case my ACTAUAL highest is 43542, so by simple math it would be (600,101).

And yes, i do have the contents of array1[] for example array1[4]=values array1[222]=values1. is this what u meant?

Yeah i know i might be very slow in this. My supervisor isnt around so i got alot of confusion and doubts.
0
xpi0t0s's Avatar, Join Date: Aug 2004
Mentor
It doesn't really matter that your supervisor isn't around; you're writing the program, not him, so it's up to you to solve these problems. You can do it; based on the code you've written so far there is nothing here you can't do. All you need is a cool rational head and to sit down and think this stuff through logically. There is nothing here you can't solve with simple algebra.

So the vertical space for the line is from 100 to 398, so you want an equation that will give 398 when you feed in 0, and 100 when you feed in 43600. Put another way, you want to find f(), where f(0)=398 and f(43600)=100.

You could simplify this by removing the inversion, so if necessary, start by finding an equation that will give you 398 when you feed in 100 and 100 when you feed in 43600. Then you just need to subtract that from something.

The array values will help you picture in your mind what the resulting histogram should look like. Also you could try outputting the scaled values as well and maybe the coordinates of the lines, so the first line of the file might read something like:
array[0]=43542; scaled=297; line=(600,398)-(600,101)
Basically you want anything in this output file that will help you (a) FIND the problem and (b) QUANTIFY the problem, and if necessary (c) post the values here with an explanation of where you're stuck so that I can give you a hint, or just the answer if it's clear you've got a mental block. But the more answers I give you the more you'll come to depend on that, so you need to start solving these yourself, and that will give you the insight and confidence that you need to get onto the next problem. So for example I gave you the expression "398-(array1[i]*398/highest)", but clearly this is a black box to you; you haven't got the faintest idea what it's doing, otherwise you'd be able to figure out how to change it to get the result you want. Maybe the problem is that you've convinced yourself that this is much more difficult than it is and are looking past all the easy answers on the grounds that they're not complicated enough. It's very common for beginners to do this, and in reality a lot of programming is really very simple.

And I bet you're wondering where I got 297 from. Hint: what do you get if you subtract it from 398?

The key to debugging is just to ask the following questions, in order:
(1) What do I expect the program to do, in quantifiable terms?
(2) Is the program doing what I expect?
(3) If not, what exactly is it doing wrong, in quantifiable terms?
(4) Why is it doing what it is doing and not what I expect?
(5) How can it be modified to do what I expect instead of what it is doing?