The principle of histogram equalization
Histogram equalization of the main idea is the histogram statistics, after the statistics, according to the specific gray values and their corresponding occurrence probability, the image of the gray scale stretching, so that the contrast of the images are expanded, as shown in the image of this classic picture.
You can see the upper left corner of the image grayscale comparison, after the histogram equalization, the lower right corner of the image of the grayscale is stretched.
The principle is that the gray values in the image are distributed in 0-255 intervals according to their probability.
The converted grayscale values are:
Among them, SK is the gray value after transformation;
RK is the gray value of the input,
NJ is the number of pixels with a gray value of J;
K is the current grayscale value with a range of 0 to L-1 (l is usually 256).
L indicates the number of gray values desirable, such as the 8bit image can represent the grayscale value has 256,l=256. For example , the picture below is the pixel value of the image, it is known that the gray value of the image is 0~7, it is required to be histogram equalization.
Here we can get the table shown in the figure below, where the number of l-1=7;pr= pixels/25;
Depending on the converted grayscale value, the original pixel value is replaced and the image becomes:
PC-side code implementation
According to the above principle, it is implemented in PC-side program as follows:
<span style= "FONT-SIZE:14PX;" >bool gethist (unsigned char *pimgdata, unsigned char *phistdata,int height,int width)
{ //This requires a non-null judgment of the input pointer, A little bit here.
int graylvl[256]={0};
float fp[256];
int i;
int sum = height*width; Calculates the total number
of pixels for (i=0; i < sum; i++) //Statistics The number of pixels in each grayscale value
{
graylvl[pimgdata[i]]++;
}
for (i=0; i < 256;i++)//calculates the specific gravity of each grayscale value
{
fp[i]= (float) graylvl[i]/(float) sum;
}
for (I=1; i < 256;i++)
{
fp[i]=fp[i-1]+fp[i];
}
for (i=0; I <m_byteofdata;i++)//equalization
{
<span style= "WHITE-SPACE:PRE;" > </span>phistdata[i]= (unsigned char) (fp[pimgdata[i]]*255.0+0.5);//plus 0.5 to be able to round the value.
}
return true;
} </span><span style= "FONT-SIZE:18PX;" >
</span>
Android Platform porting
In the Android platform, the image processing operation is implemented by JNI, which is basically consistent with the above procedure. Refer to the development of the JNI program of "Android Development"
<span style= "FONT-SIZE:14PX;" >void java_com_example_imageprocess_mainactivity_gethist (jnienv* env,jobject thiz,jbyteArray imgData, JbyteArray
Histdata, Jlong size) {jint* graylvl= (jint*) malloc (256*sizeof (jint));
jfloat* pb= (jfloat*) malloc (256*sizeof (jfloat));
unsigned char* grayhist= (unsigned char*) malloc (256*sizeof (unsigned char)); unsigned char *imgdata_buf= (*env)->getbytearrayelements (env,imgdata,0);
Gets the JNI array unsigned char *histdata_buf = (*env)->getbytearrayelements (Env,histdata, NULL);
int i;
unsigned char index=0;
memset (graylvl,0,256*sizeof (jint));
for (i=0;i<size;i++) {graylvl[imgdata_buf[i]]++;
} for (i=0;i<256;i++) {pb[i]= (jfloat) graylvl[i]/(jfloat) size;
} grayhist[0]= (unsigned char) (pb[0]*255.0+0.5);
for (i=1;i<256;i++) {pb[i]=pb[i-1]+pb[i];
grayhist[i]= (unsigned char) (pb[i]*255.0+0.5);
} for (i=0;i<size;i++) {histdata_buf[i]=grayhist[imgdata_buf[i]]; }//save the data from Histdata_buf to Histdata (*env)->setbytEarrayregion (env,histdata, 0, SIZE,HISTDATA_BUF);
Free (GRAYLVL);
Free (PB);
Free (grayhist);
}</span>
Android Code optimization Here the optimization is to optimize the floating point number to fixed-point numbers, has a certain effect.
<span style= "FONT-SIZE:14PX;" ><span style= "FONT-SIZE:18PX;" >void java_com_example_imageprocess_mainactivity_gethist (jnienv* env,jobject thiz,jbyteArray imgData, JbyteArray
Histdata, Jlong size) {jint* graylvl= (jint*) malloc (256*sizeof (jint));
jint* graylvlptr=graylvl;
unsigned int* pb= (unsigned int*) malloc (256*sizeof (unsigned int));
unsigned int *pbptr=pb;
unsigned char* grayhist= (unsigned char*) malloc (256*sizeof (unsigned char));
unsigned char *grayhistptr=grayhist+1;
unsigned char *imgdata_buf= (*env)->getbytearrayelements (env,imgdata,0);
unsigned char *imgptr=imgdata_buf;
unsigned char *histdata_buf = (*env)->getbytearrayelements (Env,histdata, NULL);
unsigned char *histptr=histdata_buf;
int i;
unsigned char index=0;
unsigned int temp = (255<<20)/size;
memset (graylvl,0,256*sizeof (jint));
for (i=size;i!=0;i--) {(* (graylvl+*imgptr)) + +;
imgptr++;
} for (i=256;i!=0;i--) {*pbptr=*graylvlptr*temp;
pbptr++;
graylvlptr++; } grayhist[0]= (PB[0]>>20];
pbptr=pb+1;
for (i=255;i!=0;i--) {*pbptr=*pbptr+* (pbPtr-1);
*grayhistptr= (*pbptr) >>20;
pbptr++;
grayhistptr++;
} imgptr=imgdata_buf;
for (i=size;i!=0;i--) {*histptr=* (grayhist+*imgptr);
imgptr++;
histptr++;
}//save the data from Histdata_buf to Histdata (*env)->setbytearrayregion (env,histdata, 0, SIZE,HISTDATA_BUF);
Free (GRAYLVL);
Free (PB);
Free (grayhist); } </span></span>
The code that is not optimized runs at 11ms, and the code runs at 9ms after optimization.
The effect of processing is as shown in the figure below, C1 is not optimized code, C2 to optimize the code, found that C2 after the operation of the results there is a certain error, although the error is small (Error 1).