图像处理之LUT表的使用

查表法的应用

比较普通算法与查LUT表法计算伽马变换和图像灰度化的快慢程度

  1. 伽马变换:
void GryImageGamaCorrect_Slow(BYTE *pGryImg,double gama,int nSize)
{
    
      
	for(int i=0;i<nSize;i++) 
	{
    
    
		*(pGryImg+i) = min(255,(int)(pow(*(pGryImg+i),gama)));
	}
	return;
}

void GryImageGamaCorrect_Fast(BYTE *pGryImg,double gama,int nSize)
{
    
    
	int LUT[256];
	int i;

	LUT[0]=0;
	for(i=1;i<256;i++) LUT[i]=min(255,(int)(pow(i,gama)));
	for(i=0;i<nSize;i++) 
	{
    
    
		*(pGryImg+i) = LUT[*(pGryImg+i)];
	}
	return;
}

在release模式下,用查表法运算一次的时间大约为0.4ms,用普通算法运算一次的时间大约为33ms;
在debug模式下,用查表法运算一次的时间大约为1.5ms,用普通算法运算一次的时间大约为35ms;
2. 图像灰度化:

void RGBImg2GryImg0(BYTE *pRGBImg,int width,int height,BYTE *pGryImg)
{
    
    
    BYTE *pRGB,*pGry,*pEnd=pRGBImg+3*width*height;
	double gry;
    for(pRGB=pRGBImg,pGry=pGryImg;pRGB<pEnd;)
	{
    
    
		gry  = *(pRGB++)*0.114; //B
		gry += *(pRGB++)*0.587; //G
		gry += *(pRGB++)*0.299; //R
		*(pGry++) = (int)(gry);
	}
    return;
}

void RGBImg2GryImg1(BYTE *pRGBImg,int width,int height,BYTE *pGryImg)//LUT
{
    
    
    BYTE *pRGB,*pGry,*pEnd=pRGBImg+3*width*height;
	double LUTR[256],LUTG[256],LUTB[256],gry;
	int i;
	
	for(i=0;i<256;i++)
	{
    
    
		LUTR[i]=0.299*i;
        LUTG[i]=0.587*i;
		LUTB[i]=0.114*i;
	}
    for(pRGB=pRGBImg,pGry=pGryImg;pRGB<pEnd;)
	{
    
    
		gry =  LUTB[*(pRGB++)];
		gry += LUTG[*(pRGB++)];
		gry += LUTR[*(pRGB++)];
		*(pGry++) = (int)(gry);
	}
    return;
}

void RGBImg2GryImg2(BYTE *pRGBImg,int width,int height,BYTE *pGryImg)
{
    
    
    BYTE *pRGB,*pGry,*pEnd=pRGBImg+3*width*height;
	int LUTR[256],LUTG[256],LUTB[256];
	int i,gry;
	
	for(i=0;i<256;i++)
	{
    
    
		LUTR[i]=(int)(0.299*i*1000);
        LUTG[i]=(int)(0.587*i*1000);
		LUTB[i]=(int)(0.114*i*1000);
	}
    for(pRGB=pRGBImg,pGry=pGryImg;pRGB<pEnd;)
	{
    
    
		gry =  LUTB[*(pRGB++)];
		gry += LUTG[*(pRGB++)];
		gry += LUTR[*(pRGB++)];
		*(pGry++) = gry/1000;
	}
    return;
}

void RGBImg2GryImg3(BYTE *pRGBImg,int width,int height,BYTE *pGryImg)
{
    
    
    BYTE *pRGB,*pGry,*pEnd=pRGBImg+3*width*height;
	int LUTR[256],LUTG[256],LUTB[256];
	int i,gry;
	
	for(i=0;i<256;i++)
	{
    
    
		LUTR[i]=(int)(0.299*i*1024);
        LUTG[i]=(int)(0.587*i*1024);
		LUTB[i]=(int)(0.114*i*1024);
	}
    for(pRGB=pRGBImg,pGry=pGryImg;pRGB<pEnd;)
	{
    
    
		gry  = LUTB[*(pRGB++)];
		gry += LUTG[*(pRGB++)];
		gry += LUTR[*(pRGB++)];
		*(pGry++) = gry>>10;
	}
    return;
}

void RGBImg2GryImg4(BYTE *pRGBImg, int width, int height, BYTE *pGryImg)
{
    
    
	BYTE *pRGB, *pEnd;
	BYTE *pGry;
	int sum;

	pEnd = pRGBImg+3*width*height;
	for (pRGB = pRGBImg, pGry = pGryImg; pRGB<pEnd;)
	{
    
    
		sum = *(pRGB++)*7471;  //B*0.114
		sum += *(pRGB++)*38469; //G*0.587
		sum += *(pRGB++)*19595; //R*0.299
		*(pGry++) = sum>>16;
	}
	return;
}

在release模式下,用查表法与移位操作运算一次的时间大约为0.7ms,用普通算法运算一次的时间大约为8.1ms;
在debug模式下,用查表法与移位操作运算一次的时间大约为3.5ms,用普通算法运算一次的时间大约为6.3ms;

均值方差规定化

代码如下:

void SetAverVar(BYTE *pImg, int width, int height, int aver0, int var0)
{
    
    
	unsigned long hist[256];
	int aver1, var1;
	CalAverVar(pImg, width, height, aver1, var1);
	BYTE *pCur = pImg, *pEnd = pImg + width * height;
	memset(hist, 0, sizeof(unsigned long) * 256);
	for (;pCur<pEnd;)
	{
    
    
		hist[min(255, (max(0, *(pCur++) - aver1))*var0 / var1 + aver0)]++;
		//G1=(g-u1)*(d0/d1)+u0;
	}
	for (int i = 0; i < width*height; i++)
	{
    
    
		*(pImg + i) = hist[*(pImg + i)];
	}
	return;
}

将所有的像素点存进表里后先减去原始均值,再改变方差,再加上规定的均值,但有个问题是如何确定输入的一对均值方差合法?比如输入均值255,那么输入的方差只能为0,输入其他的也会有输出,但实际上,代码先满足了方差的规定化,后满足均值的规定化,而在原像素上会产生溢出,限定最大值为255后,可能会出现均值也没有满足,而前一步规定好的方差也被改变的情况,目前我还没有找到解决办法。

计算图像的均值方差

代码如下:

void CalAverVar(BYTE *pImg,int width,int height,int &aver,int &var)
	{
    
    
		unsigned long hist[256];
		BYTE *pCur = pImg, *pEnd = pImg + width * height;
		memset(hist, 0, sizeof(unsigned long) * 256);
		for (; pCur < pEnd;) {
    
    
			hist[*(pCur++)]++;
		}
		int sum = 0, sum_var = 0;
		for (int i = 0; i < 256; i++)
		{
    
    
			sum += i * hist[i];
		}
		if (sum) aver = sum / (height*width);
		else aver = 0;
		for (int i = 0; i < 256; i++)
		{
    
    
			sum_var += (i - aver) * (i - aver) * hist[i];
		}
		if (sum_var) var = (int)(sqrt(sum_var / (height * width)));
		else var = 0;
		return ;
}

图像均值=像素值总和/像素个数,可以建立一个直方图表,将各点像素值作为下标,记录有多少个这样的点,再分别将下标与个数相乘即为总和。
方差=(各点像素值-均值)^2之和/像素个数,计算方法与均值类似。

用查表法计算两图像相减的绝对值;

代码如下:

	void abs1(BYTE *pImgA,BYTE *pImgB,int width,int height) 
	{
    
    
		int LUT[511];
		BYTE *pA, *pB;
		BYTE *pEndA = pImgA + width * height, *pEndB = pImgB + width * height;
		for (int i = 0; i < 256; i++)
		{
    
    
			LUT[i + 255] = LUT[255 - i] = i;
		}
		for (pA=pImgA ,pB=pImgB; pA < pEndA , pB<pEndB ; )
		{
    
    
			*(pA++) = LUT[*pA - (*pB++) + 255];
		}
}

因为两像素相减值域为512,先建一个相当于把y=|x|图像右移255个单位的图,然后直接查表。

除法的快速计算

代码如下:

	void ImgDiv_Fast(BYTE *pImgA, BYTE *pImgB, int width, int height)
	{
    
    
		int LUT[256], b;
		for (int i = 1; i < 256; i++)
			LUT[i] = (1 << 22) / i;
		for (int i = 0; i < width*height; i++)
		{
    
    
			b = *(pImgB + i);
			if (b) (*(pImgA + i))*LUT[b] >> 22;
			else *(pImgA + i) = 255;
		}
		return;
}

Y=X/N 等价与Y=X* (1/N),其中1/N=((aM)/N)/(aM),即((a<<M)/N)>>M,预先将(a<<M)/N 存进LUT表,这样A/B时,只需要给A*对应表中的值即可。
普通算法:

	void ImgDiv_Slow(BYTE *pImgA, BYTE *pImgB, int width, int height)
	{
    
    
		int b;
		for (int i = 0; i < width*height;i++)
		{
    
    
			b = *(pImgB + i);
			if (b) (*(pImgA + i)) /= b;
			else *(pImgA + i) = 255;
		}
		return;
}

猜你喜欢

转载自blog.csdn.net/qq_36587495/article/details/108165106
今日推荐