3

I need to calculate the standard deviation on an image I have inside a UIImage object. I know already how to access all pixels of an image, one at a time, so somehow I can do it. I'm wondering if there is somewhere in the framework a function to perform this in a better and more efficient way... I can't find it so maybe it doensn't exist. Do anyone know how to do this? bye

ste72
  • 45
  • 1
  • 4
  • 1
    You will have to write it yourself probably, especially considering that it would have to be a 2-dimensional standard deviation – MZimmerman6 Jul 15 '13 at 12:50

2 Answers2

4

To further expand on my comment above. I would definitely look into using the Accelerate framework, especially depending on the size of your image. If you image is a few hundred pixels by a few hundred. You will have a ton of data to process and Accelerate along with vDSP will make all of that math a lot faster since it processes everything on the GPU. I will look into this a little more, and possibly put some code in a few minutes.

UPDATE

I will post some code to do standard deviation in a single dimension using vDSP, but this could definitely be extended to 2-D

 float *imageR =  [0.1,0.2,0.3,0.4,...]; // vector of values
 int numValues = 100; // number of values in imageR
 float mean = 0; // place holder for mean
 vDSP_meanv(imageR,1,&mean,numValues); // find the mean of the vector
 mean = -1*mean // Invert mean so when we add it is actually subtraction
 float *subMeanVec  = (float*)calloc(numValues,sizeof(float)); // placeholder vector
 vDSP_vsadd(imageR,1,&mean,subMeanVec,1,numValues) // subtract mean from vector
 free(imageR); // free memory 
 float *squared = (float*)calloc(numValues,sizeof(float)); // placeholder for squared vector
 vDSP_vsq(subMeanVec,1,squared,1,numValues); // Square vector element by element
 free(subMeanVec); // free some memory
 float sum = 0; // place holder for sum
 vDSP_sve(squared,1,&sum,numValues); sum entire vector
 free(squared); // free squared vector
 float stdDev = sqrt(sum/numValues); // calculated std deviation
MZimmerman6
  • 8,445
  • 10
  • 40
  • 70
  • thank you! that's an interesting starting point! I will try... Actually I didn't know the vDSP framework... – ste72 Jul 15 '13 at 13:55
  • 1
    Yeah that should work fine. It is directly the formula for standard deviation in one dimension, so you will have to do some vector massaging to get your 2D image into 1D, but other than that, and probably a few typos in my code, you should be good. – MZimmerman6 Jul 15 '13 at 13:58
2

Please explain your query so that can come up with specific reply.

If I am getting you right then you want to calculate standard deviation of RGB of pixel or HSV of color, you can frame your own method of standard deviation for circular quantities in case of HSV and RGB.

We can do this by wrapping the values. For example: Average of [358, 2] degrees is (358+2)/2=180 degrees. But this is not correct because its average or mean should be 0 degrees. So we wrap 358 into -2. Now the answer is 0. So you have to apply wrapping and then you can calculate standard deviation from above link.

UPDATE: Convert RGB to HSV

    // r,g,b values are from 0 to 1 // h = [0,360], s = [0,1], v = [0,1]
//  if s == 0, then h = -1 (undefined)

void RGBtoHSV( float r, float g, float b, float *h, float *s, float *v )

{
 float min, max, delta;   
    min = MIN( r, MIN(g, b ));   
    max = MAX( r, MAX(g, b ));   
    *v = max;  
    delta = max - min;   
    if( max != 0 )  
        *s = delta / max;  
    else {   
        // r = g = b = 0   
        *s = 0;   
        *h = -1;   
        return; 
    }
    if( r == max )
        *h = ( g - b ) / delta; 
    else if( g == max )
        *h=2+(b-r)/delta;
    else 
        *h=4+(r-g)/delta; 
    *h *= 60;
    if( *h < 0 ) 
        *h += 360;
}

and then calculate standard deviation for hue value by this:

double calcStddev(ArrayList<Double> angles){
  double sin = 0;
  double cos = 0;
  for(int i = 0; i < angles.size(); i++){
       sin += Math.sin(angles.get(i) * (Math.PI/180.0));
       cos += Math.cos(angles.get(i) * (Math.PI/180.0)); 
  }
  sin /= angles.size();
  cos /= angles.size();

  double stddev = Math.sqrt(-Math.log(sin*sin+cos*cos));

  return stddev;

}

Krishna Kumar
  • 1,652
  • 9
  • 17
  • Hi Krishna! my image is a squared photo. I need to divide it in several smaller squares and I need a way to identify and remove those smaller squares that contains only one uniform color... for this reason I was thinking of calculating the standard deviation in order to define a threashold and dischard those under – ste72 Jul 15 '13 at 13:35
  • You can calculate hue for all the pixels of small square and then calculate standard deviation and set threshold according to you suitability (close to zero). hue values are [0, 360]. – Krishna Kumar Jul 15 '13 at 14:11