Hello,

I would like to confirm if I have the correct way of calculating the mean and standard deviation of an image. I am not sure I have the right answers. Please can someone please confirm this.

Also, I would like to ask if anyone knows how I can obtain pixel from my image. I am using OpenCV's cvLoadImage function to load the image. I am not then exactly sure how to obtain each pixel of the image using first principles. I don't want to use the Opencv function or any other library again for that.

Can someone assist me?

#include <cstdlib>
#include <stdio.h>
#include <iostream>
#include <cmath>
#include "C:\OpenCV2.1\include\opencv\cv.h"
#include "C:\OpenCV2.1\include\opencv\cvaux.h"
#include "C:\OpenCV2.1\include\opencv\cxcore.h"
#include "C:\OpenCV2.1\include\opencv\ml.h"
#include "C:\OpenCV2.1\include\opencv\cxtypes.h"
#include "C:\OpenCV2.1\include\opencv\highgui.h"

using namespace std;
typedef unsigned char uchar;


int main (int argc, char *argv[])
{

	IplImage *image;
	int height, width;
	uchar** ImageData;
	uchar* data;
	double mean, std_dev;

	cvNamedWindow("A1", 1);

	image = cvLoadImage(argv[1],1);

	//Calculate the height and width of the image
	height = image->height;
	width = image->width;
	cout << "This image has " << width << " by " << height << " pixels." << endl;
	cvGetRawData(image, (uchar**)&data);

	ImageData = new uchar* [height];
	for(int i = 0; i < height; i++)
	{
		ImageData[i] = new uchar [width];
	}

	//Calculate the mean of the image
	double total = 0;
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			//total += ImageData[i][j];
			total += data[width*image->width + height];
		}
	}
	mean = (total/ (height * width));

	cout << "Mean: " << mean  << endl;

	//Calculate the standard deviation of the image
	double var = 0;
	for (int a = 0; a < height; a++)
	{
		for (int b = 0; b < width; b++)
		{
			var += ((ImageData[a][b] - mean) * (ImageData[a][b] - mean));
			
		}
	}
	var /= (height * width);
	std_dev = sqrt(var);

	cout << "Standard Deviation: " << std_dev << endl;
	

	cvShowImage("A1", image);
	cvWaitKey(0);

	cvReleaseImage(&image);
	cvDestroyWindow("A1");

	return 0;

}

Line 49 is wrong for sure, it probably should be:

total += data[i*width + j]; //or maybe "data[j*height + i]"

At line 62, the ImageData array was never initialized, so it won't contain the actual pixel values, you should probably use data as above.

For the rest, I think you have it correct, both the mean and stddev.

Also delete the memory allocated for ImageData after you've finished.

Edited 5 Years Ago by WolfPack: n/a

Line 49 is wrong for sure, it probably should be:

total += data[i*width + j]; //or maybe "data[j*height + i]"

At line 62, the ImageData array was never initialized, so it won't contain the actual pixel values, you should probably use data as above.

For the rest, I think you have it correct, both the mean and stddev.

I think it should be, data[height * i + j]

Thank you so much for your help. I fixed it.

I want to ask (referring to Line 48) from the original code:

total += ImageData[i][j];

.

When I use this, the mean value is constantly outputting value 205 to different images. Is there another way I could write this so that it will also give me the right answer?

Hello,

I'm sorry but neither

total += data[i*width + j];

NOR

total += data[height * i + j];

gave me the right mean:-(.

Please help.

try:

total += data[height * j + i];

I think that's the right one to use.
Also, I think that by default, the opencv OpenImage function will make the images into a color image (even if it was originally a grayscale image). So, if it is the default format, then you need to jump by 3 bytes (BGR) to jump from one pixel to the next. So this would be more appropriate:

total += data[3 * (height * j + i)]; //the 3 takes this 3 bytes stride into account.

I tried that thanks. But it still gives me the wrong mean. The mean I got is 116.924 compared to the right one of 116.9404. Thanks.

>>The mean I got is 116.924 compared to the right one of 116.9404.
Well, that's not a very big difference. That's just accumulation of round-off error. It is not because your algorithm is wrong, but because it could be better. Basically, it comes from the fact that as you are adding and adding to total, it grows to a very large number. So, since the number of decimals that can be represented by a "double" is limited to about 16-20 significant digits, when "total" is very large, adding relatively small numbers to it no longer adds the correct amount because it is lost at the fringe of the precision of the variable (i.e. it gets heavily rounded-off).

One way to fix this is to use a recursive averaging formula instead. In other words, instead of accumulating all the pixel values in total and then dividing by the total number of pixels, you update an average value that is always roughly around the value of the pixel values. Here is how you could calculate the mean recursively, for a hypothetical vector v:

double average = 0;
int number_of_samples = 0;
for(int i=0; i<v.size(); ++i) {
  number_of_samples++;
  average = (average * (number_of_samples - 1) + v[i]) / number_of_samples;
};

Basically, you always take a weighted average of the previous average and the current pixel value. I guess the above formula is self-explanatory, and clearly yields the average at the end. Similarly, you can do it for the standard deviation. The advantage is that the variable "average" will always keep a value that is roughly in the same order of magnitude as the elements that are being averaged. That should improve the resulting accuracy.

Thank you so much for all your help. One last question. How would I obtain each pixel value? (I'm not exactly sure how to code that). Given the image, I could obtain the height and width using

height = image->height; 
width = image->width;

So in terms of Lines 3 and 5, I will need to obtain the total pixel size (v.size()) and each pixel value ([v(i)]) . I think to obtain the pixel size, I can just multiply the height by the width. But to get each pixel value, is a bit of a challenge.

It is actually very important for me to be able to get each pixel value of the image, because I would like to calculate the median, minimum and maximum value after I've successfully obtained the mean and standard deviation.

Thanks.

Edited 5 Years Ago by dolly_olaide: n/a

Oh. Maybe that was the problem. I was using color images. But I will convert it to greyscale and look at the link. Thanks.

Thank you all for all your help. It works now. I converted it to a greyscale image and it gives the correct mean. Thank you all (especially mike)!!:)

This question has already been answered. Start a new discussion instead.