Retinex环绕功能

时间:2016-04-12 09:59:53

标签: image-processing

我是c编程和图像处理领域的新手。我试图使用PPM图像在空间域中使用高斯环绕函数来编码单尺度视网膜。我使用的标准retinex公式如下:

  

Ri(x,y)= logIi(x,y) - log [F(x,y)* Ii(x,y)]

子指数i代表第i个光谱带,c是常数.Ri(x,y)i是Retinex输出,Ii(x,y)是输入图像分布。 第i个光谱带。

我选择了一个3x3高斯蒙版,如下所示:

  

F(x,y)= [e ^( - 2 / c ^ 2)e ^( - 1 / c ^ 2)e ^( - 2 / c ^ 2); e ^( - 1 / c ^ 2)1   e ^( - 1 / c ^ 2); e ^( - 2 / c ^ 2)e ^( - 1 / c ^ 2)e ^( - 2 / c ^ 2)]

我在卷积运算之前将环绕声功能归一化为1。在记录操作之后,我已将值重新调整回0-255,但在重建图像中对比度没有增强,而是图像很暗。请查找链接附带的原始图像和输出图像。由于StackOverflow不支持PPM图像,我已经将图像的PNG版本附加到链接。我使用Dev c ++在c中编写retinex。请告诉我是否需要更改环绕声功能或如何处理单一尺度的视网膜问题。

Original Image

您好,

我是c编程的新手,所以请原谅我,如果程序不符合标准。我用3x3高斯掩码实现了卷积,并使用了我自己的一些逻辑,这并不简单。当我使用3x3高斯掩模在空间域中进行滤波时,逻辑工作正常,因此我使用相同的逻辑来进行3x3高斯掩模的卷积。请找到用于计算空间域中彩色图像的retinex的c代码。我已经在必要时给出了合适的评论:

#include<stdio.h>
#include<stdlib.h>
#include<math.h>

typedef struct {
     unsigned char red,green,blue;
} PPMPixel;

typedef struct {
 int x, y;
 PPMPixel *data;
} PPMImage;

#define CREATOR "RPFELGUEIRAS"
#define RGB_COMPONENT_COLOR 255

static PPMImage *readPPM(const char *filename)
{
   char buff[16];
     PPMImage *img;
    // PPMImage *gaussian;
     FILE *fp;
     int c, rgb_comp_color;
     //open PPM file for reading
     fp = fopen(filename, "rb");
     if (!fp) {
      fprintf(stderr, "Unable to open file '%s'\n", filename);
      exit(1);
    }   
     //read image format
  if (!fgets(buff, sizeof(buff), fp)) {
       perror(filename);
       exit(1);
  }

//check the image format
if (buff[0] != 'P' || buff[1] != '6') {
   fprintf(stderr, "Invalid image format (must be 'P6')\n");
   exit(1);
}

//alloc memory form image
 img = (PPMImage *)malloc(sizeof(PPMImage));
 if (!img) {
      fprintf(stderr, "Unable to allocate memory\n");
       exit(1);
  }

 //check for comments
 c = getc(fp);
 while (c == '#') {
  while (getc(fp) != '\n') ;
      c = getc(fp);
 }

 ungetc(c, fp);
 //read image size information


 if (fscanf(fp, "%d %d", &img->x, &img->y) != 2) {          
        fprintf(stderr, "Invalid image size (error loading '%s')\n", filename);
      exit(1);
 }




 //read rgb component
  if (fscanf(fp, "%d", &rgb_comp_color) != 1) {
      fprintf(stderr, "Invalid rgb component (error loading '%s')\n", filename);
          exit(1);
 }

//check rgb component depth
if (rgb_comp_color!= RGB_COMPONENT_COLOR) {
     fprintf(stderr, "'%s' does not have 8-bits components\n", filename);
     exit(1);
 }

 while (fgetc(fp) != '\n') ;
 //memory allocation for pixel data

 img->data = (PPMPixel*)malloc(img->x * img->y * sizeof(PPMPixel));

 if (!img) {
        fprintf(stderr, "Unable to allocate memory\n");
      exit(1);
}

//read pixel data from file

 if (fread(img->data, 3 * img->x, img->y, fp) != img->y) {
     fprintf(stderr, "Error loading image '%s'\n", filename);
     exit(1);
 }

   fclose(fp);
   return img;
}
void writePPM(const char *filename, PPMImage *img)
{
  FILE *fp;
  //open file for output
  fp = fopen(filename, "wb");
    if (!fp) {
   fprintf(stderr, "Unable to open file '%s'\n", filename);
   exit(1);
 }

 //write the header file
 //image format
 fprintf(fp, "P6\n");

 //comments
fprintf(fp, "# Created by %s\n",CREATOR);

//image size
 fprintf(fp, "%d %d\n",img->x,img->y);

 // rgb component depth
 fprintf(fp, "%d\n",RGB_COMPONENT_COLOR);

// pixel data
fwrite(img->data, 3 * img->x, img->y, fp);
fclose(fp);
}

void changeColorPPM(int c,PPMImage *img,PPMImage *gaussian)
{
    int i,row,column,z,k=0,l=0;
    float red[9];
    float green[9];
    float blue[9];
    float min1=0,min2=0,min3=0,max1=0,max2=0,max3=0,exp1=0,exp2=0,exp3=0,exp4=0,c1=0,c2=0,c3=0,ct1=0,ct2=0,ct3=0,sum=0;
    float s1,s2,s3,s4,s5,s6;
    z=img->x;
    float *gaussian_red;
    float *gaussian_green;
    float *gaussian_blue;

    c1=(float)1/(c*c);
    c2=(float)2/(c*c);


    /* Just to avoid memory issues for float assigned maximum memory for float block to handle intermediate data in decimal*/
    gaussian_red =  (float*)malloc(15000000);
    gaussian_green = (float*)malloc(15000000);
    gaussian_blue = (float*)malloc(15000000);



    /* Used taylor series expansion to find  exponenrial values as same were not generated correctly*/
     exp1=1-pow(c1,1)+pow(c1,2)/2-pow(c1,3)/6+pow(c1,4)/24-pow(c1,5)/120+pow(c1,6)/720;
    /* Used taylor series expansion as  exponenrial values were not generated correctly*/
    exp2=1-pow(c2,1)+pow(c2,2)/2-pow(c2,3)/6+pow(c2,4)/24-pow(c2,5)/120+pow(c1,6)/720;

    /* Sum of all the gaussian values are calculated just to normalize the 3x3 gassian mask  to 1 */
    sum=1+4*exp1+4*exp2;

    /* Calculating equivalent pixel value after convolution with 3x3 gaussian mask in spatial domain */
    for(i=0;i<img->x*img->y;i++){
        row=0;
        column=0;
        s1=0,s2=0,s3=0,s4=0,s5=0,s6=0,exp1,exp2;
        row=i/(img->x);
        column=i%(img->x);

        red[9]={0};
        green[9]={0};
        blue[9]={0};

        /* as equivalent gaussian values for a pixel will be gaussian. 
        Storing corresponding pixel value in float array */ 

        gaussian_red[i]=0;
        gaussian_green[i]=0;
        gaussian_blue[i]=0;


        /* When a pixel is multiplied by a 3x3 gaussian mask, the pixel of interest is multiplied by centre of 3x3 
        gaussian mask which is 1 and remaining weights of gaussian masks are multiplied with neighbouring pixels.
        If the  pixel 'i' of interest is present in 1 row , last row, 1st column or last column then all the 3x3
         gaussian weightsmay not find neighbouring pixels in image to get multiplied with. So below we are checking whether
         pixel i is having all the neighbour pixel values to be multiplied with gaussian mask*/

        /* Checking whether Gaussian weight having location (-1,-1)  is fitting with any pixel in image otherwise 
           setting corresponding value to 0. We are checking if i-z-1<0 which indicates  1 row and i%(numberofcolumns)=0
           which indicates 1 column. If its 1st row or 1st column then i-z-1 pixel will not be present in image so setting 
           corresponding product to 0. */ 
        if (i-z-1<0 || (i%z)==0)
        { 
            red[0]=0;
            green[0]=0;
            blue[0]=0;

        }
        /*If Gaussian mask having location (-1,-1) fits any pixel value in image then multiplying gaussian weight 
          with that pixel value. Here 'z' is the total number of column. we are multiplying gaussian mask
         (-1,-1) with pixel having location (i-z-1) */
        else 
        {
            red[0]=img->data[i-z-1].red*exp2;
            green[0]=img->data[i-z-1].green*exp2;
            blue[0]=img->data[i-z-1].blue*exp2;

        }

        /* Checking whether Gaussian mask having location (0,-1)  is fitting with any pixel in image otherwise 
           setting corresponding value to 0. We are checking if i-z<0 which indicates  1 row and when its 1st row 
           i-z pixel will not be not be present in image so setting 
           corresponding product to 0*/ 
        if(i-z<0)
        { 
            red[1]=0;
            green[1]=0;
            blue[1]=0;
        }
        /*If Gaussian mask having location (0,-1) fits any pixel value in image then multiplying 
         same with that pixel value. Here 'z' is the total number of column. we are multiplying gaussian mask
         (0,-1) with pixel having location (i-z) */
        else 
        {
            red[1]=img->data[i-z].red*exp1;
            green[1]=img->data[i-z].green*exp1;
            blue[1]=img->data[i-z].blue*exp1; 

        }
        /* Checking whether Gaussian mask having location (1,-1)  is fitting with any pixel in image otherwise 
           setting corresponding value to 0. We are checking if i-z11<0 which indicates  1 row and i%(numberofcolumns-1)=0
           which indicates last column. If its 1st row or last column then i-z+1 pixel will not be present in image so 
           setting corresponding product to 0. */ 
        if (i-z+1<0|| i%(z-1)==0)
        { 
            red[2]=0;
            green[2]=0;
            blue[2]=0;
        }
        /*If Gaussian mask having location (1,-1) fits any pixel value in image then multiplying 
         same with that pixel value. Here 'z' is the total number of column. we are multiplying gaussian mask
         (1,-1) with pixel having location (i-z+1) */
        else 
        {
            red[2]=img->data[i-z+1].red*exp2;
            green[2]=img->data[i-z+1].green*exp2;
            blue[2]=img->data[i-z+1].blue*exp2;


        }
        /* Checking whether Gaussian mask having location (-1,0)  is fitting with any pixel in image otherwise 
           setting corresponding value to 0. We are checking if i%z=0 which indicates  1 column a. If its 1st column 
           then i-z pixel will not be present in image so setting corresponding product to 0. */ 
        if (i%(z)==0)
        { 
            red[3]=0;
            green[3]=0;
            blue[3]=0;
        }
        /*If Gaussian mask having location (-1,0) fits any pixel value in image then multiplying 
         same with that pixel value. Here 'z' is the total number of column. we are multiplying gaussian mask
         (-1,0) with pixel having location (i-1) */
        else 
        {
            red[3]=img->data[i-1].red*exp1;
            green[3]=img->data[i-1].green*exp1;
            blue[3]=img->data[i-1].blue*exp1;

        } 
        /* This is the particular pixel of interest so we are multiplying with centre of gaussian mask having weight 1 */ 

            red[4]=(float)img->data[i].red;
            green[4]=(float)img->data[i].green;
            blue[4]=(float)img->data[i].blue;

        /* Checking whether Gaussian mask having location (1,0)  is fitting with any pixel in image otherwise 
           setting corresponding value to 0. We are checking if i%(z-1)<0 which indicates last column.
            If its 1st row or last column then i+1 pixel will not be present in image so setting 
           corresponding product to 0. */ 
        if (i!=0 && i%(z-1)==0)
        { 
            red[5]=0;
            green[5]=0;
            blue[5]=0;
        }
        /*If Gaussian mask having location (1,0) fits any pixel value in image then multiplying 
         same with that pixel value. Here 'z' is the total number of column. we are multiplying gaussian mask
         (1,0) with pixel having location (i+1) */
        else 
        {
            red[5]=img->data[i+1].red*exp1;
            green[5]=img->data[i+1].green*exp1;
            blue[5]=img->data[i+1].blue*exp1;    
        }
        /* Checking whether Gaussian mask having location (-1,1)  is fitting with any pixel in image otherwise 
           setting corresponding value to 0. We are checking if i+z-1>(Totalnumberofpixels) which indicates  last row and i%(numberofcolumns-1)=0
           which indicates last column. If its last row or 1st column then i+z-1 pixel will not be present in image so 
           setting corresponding product to 0. */ 
        if ((i+z-1>img->x*img->y)|| i%z==0)
        { 
            red[6]=0;
            green[6]=0;
            blue[6]=0;
        }
        /*If Gaussian mask having location (-1,1) fits any pixel value in image then multiplying 
         same with that pixel value. Here 'z' is the total number of column. we are multiplying gaussian mask
         (-1,1) with pixel having location (i+z-1) */
        else 
        {
            red[6]=img->data[i+z-1].red*exp2;
            green[6]=img->data[i+z-1].green*exp2;
            blue[6]=img->data[i+z-1].blue*exp2; 
        }
        /* Checking whether Gaussian mask having location (0,1)  is fitting with any pixel in image otherwise 
           setting corresponding value to 0. We are checking if i+z>(Totalnumberofpixels) which indicates last row. 
           If its last row then i+z pixel will not be present in image so setting 
           corresponding product to 0. */ 
        if ((i+z)>img->x*img->y)
        { 
            red[7]=0;
            green[7]=0;
            blue[7]=0;
         }
        /*If Gaussian mask having location (0,1) fits any pixel value in image then multiplying 
         same with that pixel value. Here 'z' is the total number of column. we are multiplying gaussian mask
         (0,1) with pixel having location (i+z) */
        else
        {
            red[7]=img->data[i+z].red*exp1;
            green[7]=img->data[i+z].green*exp1;
            blue[7]=img->data[i+z].blue*exp1;
        }
        /* Checking whether Gaussian mask having location (1,1)  is fitting with any pixel in image otherwise 
           setting corresponding value to 0. We are checking if i+z+1>(Totalnumberofpixels) which indicates last row. 
           and i%(numberofcolumns-1)=0 whic =h indicates last row.If its last row and last column
           then i+z+1 pixel will not be present in image so setting corresponding product to 0. */ 
        if ((i+z+1>img->x*img->y|| i%(z-1)==0) && i!=0)
        { 
            red[8]=0;
            green[8]=0;
            blue[8]=0;
        }
        /*If Gaussian mask having location (1,1) fits any pixel value in image then multiplying 
         same with that pixel value. Here 'z' is the total number of column. we are multiplying gaussian mask
         (1,1) with pixel having location (i+z+1) */
        else 
        {
            red[8]=img->data[i+z+1].red*exp2;
            green[8]=img->data[i+z+1].green*exp2;
            blue[8]=img->data[i+z+1].blue*exp2;             
        }

        // Normalising sum of gaussian values of red channel by dividing with sum of  all weights of gaussian mask
        s1=(red[0]+red[1]+red[2]+red[3]+red[4]+red[5]+red[6]+red[7]+red[8])/sum;
        // Normalising sum of gaussian values of green channel  by dividing with sum of  all weights of gaussian mask
        s2=(green[0]+green[1]+green[2]+green[3]+green[4]+green[5]+green[6]+green[7]+green[8])/sum;
        // Normalising sum of gaussian values of blue channel  by dividing with sum of  all weights of gaussian mask
        s3=(blue[0]+blue[1]+blue[2]+blue[3]+blue[4]+blue[5]+blue[6]+blue[7]+blue[8])/sum;

        gaussian_red[i]=(float)s1;
        gaussian_green[i]=(float)s2;
        gaussian_blue[i]=(float)s3;

        //Applying retinex function
        s4=log(img->data[i].red+1)-log(s1+1);
        s5=log(img->data[i].green)-log(s2+1);
        s6=log(img->data[i].blue)-log(s3+1);

        gaussian_red[i]=(float)s4;
        gaussian_green[i]=(float)s5;
        gaussian_blue[i]=(float)s6;

    }


        max1=0;
        max2=0;
        max3=0;
                    /* FInding maximum  values for red,green and blue channels */
        for(i=0;i<img->x*img->y;i++)
        {   

            if(gaussian_red[i]>max1)
            {
                max1=gaussian_red[i];
            }
                if(gaussian_green[i]>max2)
            {
                max2=gaussian_green[i];
            }
                if(gaussian_blue[i]>max3)
            {
                    max3=gaussian_blue[i];
            }

        }



        min1=0;
        min2=0;
        min3=0;
        /* Calculating minimum values for all 3 channels after applying retinex formula*/
        for(i=0;i<img->x*img->y;i++)
        {   

            if(gaussian_red[i]<min1)
            {
                min1=gaussian_red[i];                   
            }
            if(gaussian_green[i]<min2)
            {
                min2=gaussian_green[i];                         
            }
            if(gaussian_blue[i]<min3)
            {
                min3=gaussian_blue[i];
            }

        }

        /*Adding minimum values from above step to all pixel value. This is done as part of rescaling
         the values from decimal back to 0-255*/
        for(i=0;i<img->x*img->y;i++)
        {           
            gaussian_red[i]=gaussian_red[i]-min1;
            gaussian_green[i]=gaussian_green[i]-min2;               
            gaussian_blue[i]=gaussian_blue[i]-min3;

        }



        printf("the maximum values are %f,%f,%f\n",max1,max2,max3); 
        /* Rescaling decimal data back to 0-255 for all three channels*/
        for(i=0;i<img->x*img->y;i++)
        {   
            printf("the values before are %d,%d,%d\n",img->data[i].red,img->data[i].green,img->data[i].blue);
            img->data[i].red=(gaussian_red[i]*255/(max1-min1));
            img->data[i].green=(gaussian_green[i]*255/(max2-min2));     
            img->data[i].blue=(gaussian_blue[i]*255/(max3-min3));
            printf("the values after are %d,%d,%d\n",img->data[i].red,img->data[i].green,img->data[i].blue);
         }


 }


int main(int argc, char *argv[]){
   int c;  
   c=atoi(argv[3]);
   PPMImage *image; 
   image = readPPM(argv[1]);   
   changeColorPPM(c,image,image); 
    writePPM(argv[2],image);

    }

1 个答案:

答案 0 :(得分:0)

就图像处理而言,您的解决方案似乎是正确的。

最后的缩放似乎有问题 - 但是你仍然很难获得可见的结果。

多分钟/最大值似乎错了,可以减少到一个:

find min/max for each channel
for(each pixel) newvalue=255*(oldvalue-min)/(max-min)

 for(i=0;i<img->x*img->y;i++) {
   img->data[i].red=255*(gaussian_red[i]-min1)/(max1-min1);
   img->data[i].green=255*(gaussian_green[i]-min2)/(max2-min2);     
   img->data[i].blue=255*(gaussian_blue[i]-min3)/(max3-min3);
 }