gamma校正

来源:互联网 发布:网络监管新规 编辑:程序博客网 时间:2024/04/29 15:55

首先解读下IplImage 的结构:

typedef struct _IplImage
{
int nSize; /* IplImage大小,等于width*height */
int ID; /* 版本 (=0)*/
int nChannels; /* 大多数OpenCV函数支持1,2,3 或 4 个通道 */
int alphaChannel; /* 被OpenCV忽略 */
int depth; /* 像素的位深度: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U, IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F 可支持 */
char colorModel[4]; /* 被OpenCV忽略 */
char channelSeq[4]; /* 同上 (ditto)*/
int dataOrder; /* 0 - 交叉存取颜色通道, 1 - 分开的颜色通道. cvCreateImage只能创建交叉存取图像 */
int origin; /* 0 - 顶—左结构,1 - 底—左结构 (Windows bitmaps 风格) */
int align; /* 图像行排列 (4 or 8). OpenCV 忽略它,使用 widthStep 代替 */
int width; /* 图像宽像素数 */
int height; /* 图像高像素数*/
struct _IplROI *roi; /* 图像感兴趣区域. 当该值非空只对该区域进行处理 */
struct _IplImage *maskROI; /* 在 OpenCV中必须置NULL */
void *imageId; /* 同上*/
struct _IplTileInfo *tileInfo; /*同上*/
int imageSize; /* 图像数据大小(在交叉存取格式下imageSize=image->height*image->widthStep),单位字节*/
char *imageData; /*指向排列的图像数据 */
int widthStep; /* 排列的图像行大小,以字节为单位 */
int BorderMode[4]; /* 边际结束模式, 被OpenCV忽略 */
int BorderConst[4]; /* 同上 */
char *imageDataOrigin; /* 指针指向一个不同的图像数据结构(不是必须排列的),是为了纠正图像内存分配准备的 */
}

depth代表颜色深度,使用的是以下定义的宏,nChannels是通道数,为1,2,3或4。 
depth的宏定义: 
IPL_DEPTH_8U,无符号8bit整数(8u) 
IPL_DEPTH_8S,有符号8bit整数(8s) 
IPL_DEPTH_16S,有符号16bit整数(16s) 
IPL_DEPTH_32S,有符号32bit整数(32s) 
IPL_DEPTH_32F,32bit浮点数,单精度(32f) 
IPL_DEPTH_64F,64bit浮点数,双精度(64f)


注意,因为imageData的类型是char *,所以在利用指针读数据时,前面要进行对应的类型转换,如单通道字节型图像对应:

((uchar*)(img->imageData+i*img->widthStep))[j];

单通道浮点型图像对应:

((float*)(img->imageData+i*img->widthStep))[j];

多通道字节型图像对应:

((uchar *) (img->imageData + i*img->widthStep))[j*img->nChannels + 0] = 111;// B((uchar *) (img->imageData + i*img->widthStep))[j*img->nChannels + 1] = 112;// G((uchar *) (img->imageData + i*img->widthStep))[j*img->nChannels + 2] = 113;// R

然后直接上公式f(I)=I^gamma,I为原图像素值,f(I)为gamma校正后的像素值。

gamma<1在高灰度值区域内,动态范围变小,图像对比度降低,图像整体灰度值变大,显得亮一些;gamma>1在低灰度值区域内,动态范围变小,图像对比度降低,图像整体灰度值变小,变得暗淡。


gamma校正的实现代码如下:

#include <cv.h>#include <cxcore.h>#include <highgui.h>#include <time.h>#define DirectIplImage *srcImg = NULL, *dstImg = NULL;float gGamma = 2.2;void GammaCorrect(IplImage* src,IplImage* dst,float gamma);int main(int argc, char* argv[]){clock_t start,end;// 以灰度图为例srcImg = cvLoadImage("D:\\Documents\\Visual Studio 2012\\Projects\\opencvtest\\opencvtest\\lena.jpg",0);dstImg = cvCreateImage(cvGetSize(srcImg), 8, 1);cvNamedWindow("src");cvShowImage("src", srcImg);start = clock();GammaCorrect(srcImg,dstImg,gGamma);end = clock();printf("time = %2.4fs\n",(double)(end-start)/CLK_TCK);cvNamedWindow("dst");cvShowImage("dst", dstImg);cvWaitKey(0);cvReleaseImage(&srcImg);cvReleaseImage(&dstImg);cvDestroyWindow("src");cvDestroyWindow("dst");return 0;}void GammaCorrect(IplImage* src,IplImage* dst,float gamma){int height=src->height;  int width=src->width;  #ifdef Get2DCvScalar s;#endiffloat f;for(int i=0; i < height; i++){  //p为当前行首指针unsigned char* p1=(unsigned char*)src->imageData + src->widthStep * i;unsigned char* p2=(unsigned char*)dst->imageData + dst->widthStep * i;for(int j = 0; j < width; j++) {  #ifdef Get2Df = (cvGet2D(src,i,j).val[0]+0.5)/256;f = powf(f,gamma);s.val[0] = (int)(f*256-0.5);cvSet2D(dst,i,j,s);#endif#ifdef Directf = ((*p1++)+0.5)/256;f = powf(f,gamma);*p2++ = (int)(f*256-0.5);#endif}  }  }

采用#define Direct的像素值获取方式,耗时0.022ms,采用#define Get2D的像素值获取方式,耗时0.1ms。使用cvGet2D的方式会较为耗时。

gamma效果图如下:



若采用查表法的方式,不用对每个像素点都做gamma校正的计算,实际只计算了256次gamma校正,用查表的方式完成映射节省了计算资源,可以减少gamma校正的计算复杂度。

查表法代码如下:

#include <cv.h>#include <cxcore.h>#include <highgui.h>#include <time.h>IplImage *srcImg = NULL, *dstImg = NULL;float gGamma = 2.2;int gGammaLUT[256];// 建立gamma校正查找表void BuildTable(float gamma);// 用查表法做gamma变换void GammaCorrect(IplImage* src,IplImage* dst);int main(int argc, char* argv[]){clock_t start,end;// 以灰度图为例srcImg = cvLoadImage("D:\\Documents\\Visual Studio 2012\\Projects\\opencvtest\\opencvtest\\lena.jpg",0);dstImg = cvCreateImage(cvGetSize(srcImg), 8, 1);cvNamedWindow("src");cvShowImage("src", srcImg);start = clock();BuildTable(gGamma);GammaCorrect(srcImg,dstImg);end = clock();printf("time = %2.4fs\n",(double)(end-start)/CLK_TCK);cvNamedWindow("dst");cvShowImage("dst", dstImg);cvWaitKey(0);cvReleaseImage(&srcImg);cvReleaseImage(&dstImg);cvDestroyWindow("src");cvDestroyWindow("dst");return 0;}//根据gamma的值建立查找表void BuildTable(float gamma){int i;float f;for(i=0;i<256;i++){//预补偿,归一化,还原f = (i+0.5)/256;f = powf(f,gamma);gGammaLUT[i] = (int)(f*256-0.5);}}void GammaCorrect(IplImage* src,IplImage* dst){int height=src->height;  int width=src->width;  for(int i=0; i < height; i++){  //p为当前行首指针unsigned char* p1=(unsigned char*)src->imageData + src->widthStep * i;unsigned char* p2=(unsigned char*)dst->imageData + dst->widthStep * i;for(int j = 0; j < width; j++) {  *p2++ = gGammaLUT[(int)(*p1++)];}  }  }


 在采用#define Direct的像素值获取方式,耗时0.001ms


1 0