图像放大快速算法
发布时间:2020-12-13 20:22:09 所属栏目:PHP教程 来源:网络整理
导读:图象放大快速算法实现的原理主要有以下两点: 1、横向缩放与纵向缩放分开,而前后顺序取决于缩放前后的图象比例: 若SrcHeight/DstWidthSrcWidth/DstWidth,则先纵向缩放,否则横向缩放。 2、利用整数运算代替浮点运算,由因而分步缩放,以横向缩放为例,利用
图象放大快速算法实现的原理主要有以下两点: 1、横向缩放与纵向缩放分开,而前后顺序取决于缩放前后的图象比例: 若SrcHeight/DstWidth>SrcWidth/DstWidth,则先纵向缩放,否则横向缩放。 2、利用整数运算代替浮点运算,由因而分步缩放,以横向缩放为例,利用2次线性插值公式,再变形1下以下: f(i,j+v) = (1-v)f(i,j) +vf(i,j+1); 其中i为第i行,j为第j列,v表示求得放大后坐标的小数部份。 这里最重要的并没有直接用小数运算,而是通过将小数区间(0,1)映照到整数区间(0,128), 再利用整数来代替小数运算,最后只需要相应的处理1下就能够了。
误差分析: 首先2次线性算法本来就有误差,这里主要讨论利用整数代替小数的误差,可以看到每个整数能代替的小数范围为1/128,所以误差范围为[⑴/256,1/256]之间。
代码实现: //ImageScale.h #define IN
#define OUT
#define _DWORD int
#define _BYTE byte
#define _WORD short
struct ImageInfo
{
byte* pRGBData;
int nHeight;
int nStepValue;
int nWidth;
// int nFlag;
ImageInfo()
{
pRGBData=NULL;
}
ImageInfo(byte *p,int h,int s,int w)
{
// pRGBData = (byte*)malloc(h*s);
pRGBData = p;
nHeight=h;
nStepValue=s;
nWidth=w;
}
};
class ImageScale
{
public:
ImageScale(void);
virtual ~ImageScale(void);
void Run(BYTE* pSrcImage,int nSrcWidth,int nSrcHeight,BYTE* pTagImage,int nTagWidth,int nTagHeight,int nChannels);
private:
bool DstInSrcIndex(int large_len,int little_len,int* a3_pIntValue,byte* a4_pByteValue);
int DoubleToInt(double d);
BOOL HorizontalFill(IN ImageInfo& SrcImageInfo,IN int nTagHeight,IN int nTagWidth,IN int nTagStepValue,IN int bFlag,IN int* pIntValue,IN byte* pByteValue,OUT ImageInfo& DstImageInfo,int nChannels);
BOOL VerticalFill(IN ImageInfo& SrcImageInfo,int nChannels);
void HorizontalScale(byte *a1_pData_Src,byte *a2_pData_Dst,int nHeight,int nWidth,int *a5_pData_Unknow,byte *a6_pData_Unknow,int srcStepValue,int dstStepValue,short *a10_pData_Unknow,int nChannels);
void VerticalScale(byte *a1_pData_Src,int a3_nHeight,int a4_nWidth,int a7_nWidth,int a8_nWidthScrible,int nChannels);
};
//ImageScale.cpp
#include "StdAfx.h"
#include "ImageScale.h"
short g_pHSDataByte[]=
{
0x4000,0x0000,0x3F80,0x0080,0x3F00,0x0100,0x3E80,0x0180,0x3E00,0x0200,0x3D80,0x0280,0x3D00,0x0300,0x3C80,0x0380,0x3C00,0x0400,0x3B80,0x0480,0x3B00,0x0500,0x3A80,0x0580,0x3A00,0x0600,0x3980,0x0680,0x3900,0x0700,0x3880,0x0780,0x3800,0x0800,0x3780,0x0880,0x3700,0x0900,0x3680,0x0980,0x3600,0x0A00,0x3580,0x0A80,0x3500,0x0B00,0x3480,0x0B80,0x3400,0x0C00,0x3380,0x0C80,0x3300,0x0D00,0x3280,0x0D80,0x3200,0x0E00,0x3180,0x0E80,0x3100,0x0F00,0x3080,0x0F80,0x3000,0x1000,0x2F80,0x1080,0x2F00,0x1100,0x2E80,0x1180,0x2E00,0x1200,0x2D80,0x1280,0x2D00,0x1300,0x2C80,0x1380,0x2C00,0x1400,0x2B80,0x1480,0x2B00,0x1500,0x2A80,0x1580,0x2A00,0x1600,0x2980,0x1680,0x2900,0x1700,0x2880,0x1780,0x2800,0x1800,0x2780,0x1880,0x2700,0x1900,0x2680,0x1980,0x2600,0x1A00,0x2580,0x1A80,0x2500,0x1B00,0x2480,0x1B80,0x2400,0x1C00,0x2380,0x1C80,0x2300,0x1D00,0x2280,0x1D80,0x2200,0x1E00,0x2180,0x1E80,0x2100,0x1F00,0x2080,0x1F80,0x2000,0x0000
};
ImageScale::ImageScale(void)
{
}
ImageScale::~ImageScale(void)
{
}
void ImageScale::Run(BYTE* pSrcImage,int nChannels)
{
if (!(nChannels==1||nChannels==4))
return;
if(nSrcWidth<=0 || nSrcHeight<=0 )
return;
if(nTagWidth<nSrcWidth || nTagHeight<nSrcHeight)
return;
int nSrcStepValue=(nSrcWidth+15) & ~15;
int nTagStepValue=nTagWidth;
//申请4个内存空间
int* pIntValueTmp_nHeight = (int*)malloc(nTagHeight*sizeof(int));//存储纵坐标索引值
if (pIntValueTmp_nHeight)
{
memset(pIntValueTmp_nHeight,nTagHeight*sizeof(int));
}
byte* pByteValueTmp_nHeight = (byte*)malloc(nTagHeight);//存储纵坐标下的小数映照到整数空间下的值
if (pByteValueTmp_nHeight)
{
memset(pByteValueTmp_nHeight,nTagHeight);
}
int* pIntValueTmp_nWidth = (int*)malloc(nTagWidth*sizeof(int));//存储横坐标索引值
if (pIntValueTmp_nWidth)
{
memset(pIntValueTmp_nWidth,nTagWidth*sizeof(int));
}
byte* pByteValueTmp_nWidth = (byte*)malloc(nTagWidth);//存储横坐标下的小数映照到整数空间下的值
if (pByteValueTmp_nWidth)
{
memset(pByteValueTmp_nWidth,nTagWidth);
}
DstInSrcIndex(nTagWidth,nSrcWidth,pIntValueTmp_nWidth,pByteValueTmp_nWidth);
DstInSrcIndex(nTagHeight,nSrcHeight,pIntValueTmp_nHeight,pByteValueTmp_nHeight);
int nValueTmp1 = nSrcHeight * nTagWidth;
int nValueTmp2 = nSrcWidth * nTagHeight;
ImageInfo SrcImageInfo(pSrcImage,nSrcStepValue,nSrcWidth);
ImageInfo ImageInfo_Tmp1;
ImageInfo ImageInfo_Tmp2;
if (nValueTmp1 > nValueTmp2)
{
VerticalFill(SrcImageInfo,nTagHeight,nTagWidth,nTagStepValue,pByteValueTmp_nHeight,ImageInfo_Tmp1,nChannels);
HorizontalFill(ImageInfo_Tmp1,pByteValueTmp_nWidth,ImageInfo_Tmp2,nChannels);
}
else
{
HorizontalFill(SrcImageInfo,1,nChannels);
VerticalFill(ImageInfo_Tmp1,nChannels);
}
//pTagImage=(byte*)malloc(nTagHeight * nTagWidth);
for (int i=0; i<nTagHeight; i++)
{
memcpy(pTagImage +nChannels*i*nTagWidth,ImageInfo_Tmp2.pRGBData+ nChannels*i*nTagWidth,nChannels*nTagWidth);
}
//【释放堆内存】
if (pIntValueTmp_nHeight)
{
free(pIntValueTmp_nHeight);
pIntValueTmp_nHeight = NULL;
}
if (pByteValueTmp_nHeight)
{
free(pByteValueTmp_nHeight);
pByteValueTmp_nHeight = NULL;
}
if (pIntValueTmp_nWidth)
{
free(pIntValueTmp_nWidth);
pIntValueTmp_nWidth = NULL;
}
if (pByteValueTmp_nWidth)
{
free(pByteValueTmp_nWidth);
pByteValueTmp_nWidth = NULL;
}
if (ImageInfo_Tmp1.pRGBData)
{
free(ImageInfo_Tmp1.pRGBData);
ImageInfo_Tmp1.pRGBData = NULL;
}
if (ImageInfo_Tmp2.pRGBData)
{
free(ImageInfo_Tmp2.pRGBData);
ImageInfo_Tmp2.pRGBData = NULL;
}
}
bool ImageScale::DstInSrcIndex(int large_len,byte* a4_pByteValue)
{
int nValueTmp3 = (little_len << 7) - 128;
for (int index = 0; index<large_len; ++index)
{
float doubleValueTmp3 = ((float)index + 0.5) / ((float)large_len);
int nValueTmp4 = (int)(doubleValueTmp3 * (little_len - 0.5f) * 128.0+0.5f);
int nValueTmp1= nValueTmp3;
if(!(nValueTmp3<nValueTmp4))
nValueTmp1= nValueTmp4;
a3_pIntValue[index] = nValueTmp1 >> 7;
a4_pByteValue[index] = nValueTmp1 & 0x7F;
}
return true;
}
BOOL ImageScale::HorizontalFill(IN ImageInfo& SrcImageInfo,int nChannels)
{
int nHeightTmp1 = 0;
if (bFlag)
{
nHeightTmp1 = SrcImageInfo.nHeight;
}
else
{
nHeightTmp1 = nTagHeight;
}
//申请额外的空间保证内存对齐
int StepValueTmp=(SrcImageInfo.nStepValue+15) & ~15;
byte *pSrcImageTmp=(byte*)malloc(nChannels * StepValueTmp * nHeightTmp1);
memset(pSrcImageTmp,nChannels * StepValueTmp * nHeightTmp1);
int SumTmp1=nChannels * StepValueTmp,SumTmp2=nChannels * SrcImageInfo.nWidth;
for(int i=0;i<nHeightTmp1;i++)
{
memcpy(pSrcImageTmp+i*SumTmp1,SrcImageInfo.pRGBData+i*SumTmp2,SumTmp2);
}
// ImageInfo SrcImageInfo(pSrcImageTmp,SrcImageInfo.nHeight,StepValueTmp,SrcImageInfo.nWidth);
//调用HorizontalScale进行水平延伸,结果保存到DstImageInfo中
DstImageInfo.nHeight = nHeightTmp1;
DstImageInfo.nWidth = nTagWidth;
DstImageInfo.nStepValue = nTagStepValue;
DstImageInfo.pRGBData = (byte*)malloc(nChannels * DstImageInfo.nHeight * DstImageInfo.nStepValue);
byte* pDataSrc = SrcImageInfo.pRGBData;
byte* pDataDst = DstImageInfo.pRGBData;
HorizontalScale(pSrcImageTmp,pDataDst,DstImageInfo.nHeight,DstImageInfo.nWidth,pIntValue,pByteValue,SrcImageInfo.nStepValue,DstImageInfo.nStepValue,g_pHSDataByte,nChannels);
if (pSrcImageTmp)
{
free(pSrcImageTmp);
pSrcImageTmp=NULL;
}
return TRUE;
}
BOOL ImageScale::VerticalFill(IN ImageInfo& SrcImageInfo,int nChannels)
{
int nWidthTmp1 = 0;
int nStepValueTmp1 = 0;
if (bFlag)
{
nWidthTmp1 = nTagWidth;
nStepValueTmp1 = nTagStepValue;
}
else
{
nWidthTmp1 = SrcImageInfo.nWidth;
nStepValueTmp1 = SrcImageInfo.nStepValue;
}
//申请额外的空间保证内存对齐
int StepValueTmp=(SrcImageInfo.nStepValue+15) & ~15;
byte *pSrcImageTmp=(byte*)malloc(nChannels * StepValueTmp *( SrcImageInfo.nHeight+1));// 多申请1层来保证内存不会泄漏
memset(pSrcImageTmp,nChannels * StepValueTmp * (SrcImageInfo.nHeight+1));
int SumTmp1=nChannels * StepValueTmp,SumTmp2=nChannels * SrcImageInfo.nWidth,SumTmp3=nChannels * SrcImageInfo.nStepValue;
for(int i=0;i<SrcImageInfo.nHeight;i++)
{
memcpy(pSrcImageTmp+i*SumTmp1,SrcImageInfo.pRGBData+i*SumTmp3,SumTmp2);
}
// 最后1层用上1层填充
memcpy(pSrcImageTmp+SrcImageInfo.nHeight*SumTmp1,SrcImageInfo.pRGBData+(SrcImageInfo.nHeight⑴)*SumTmp3,SumTmp2);
DstImageInfo.nHeight = nTagHeight;
DstImageInfo.nWidth = nWidthTmp1;
DstImageInfo.nStepValue = nStepValueTmp1;
DstImageInfo.pRGBData = (byte*)malloc( nChannels * DstImageInfo.nHeight*DstImageInfo.nStepValue);
memset(DstImageInfo.pRGBData,nChannels * DstImageInfo.nHeight*DstImageInfo.nStepValue);
VerticalScale(pSrcImageTmp,DstImageInfo.pRGBData,nChannels);
if (pSrcImageTmp)
{
free(pSrcImageTmp);
pSrcImageTmp=NULL;
}
return TRUE;
}
void ImageScale::HorizontalScale(byte *a1_pData_Src,int nChannels)
{
int v17,v18,v19,v20;
int srcstep,dststep,index1,index2,index3;
if(nChannels==4)
{
srcstep=( dstStepValue<<2);
dststep=(srcStepValue<<2);
for (int i=0;i<nHeight;i++)
{
for(int j=0;j<nWidth;j++)
{
v17 = a5_pData_Unknow[j]; // 遍历,顺次取得int表数据
v18 = ( a6_pData_Unknow[j]<<1);
index1=((v17+1)<<2);
index2=(v17<<2);
index3=(j<<2);
//blue通道
v19 = a1_pData_Src[index1+MT_BLUE] * a10_pData_Unknow[v18 + 1]; // 加上小数位的精度
v20 = (v19 + a10_pData_Unknow[v18] * a1_pData_Src[index2+MT_BLUE] + 0x2000) >> 14; //0x2000右移14位为0.5,这里是为了4舍5入;
a2_pData_Dst[index3+MT_BLUE] =v20&0xff;
//green通道
v19 = a1_pData_Src[index1+MT_GREEN] * a10_pData_Unknow[v18 + 1];
v20 = (v19 + a10_pData_Unknow[v18] * a1_pData_Src[index2+MT_GREEN] + 0x2000) >> 14;
a2_pData_Dst[index3+MT_GREEN] =v20&0xff;
//red通道
v19 = a1_pData_Src[index1+MT_RED] * a10_pData_Unknow[v18 + 1];
v20 = (v19 + a10_pData_Unknow[v18] * a1_pData_Src[index2+MT_RED] + 0x2000) >> 14;
a2_pData_Dst[index3+MT_RED] =v20&0xff;
a2_pData_Dst[index3+MT_ALPHA] =255;
}
a2_pData_Dst +=srcstep;
a1_pData_Src +=dststep ;
}
}
else
{
for (int i=0;i<nHeight;i++)
{
for(int j=0;j<nWidth;j++)
{
v17 = a5_pData_Unknow[j]; // 遍历,顺次取得int表数据
v18 = ( a6_pData_Unknow[j]<<1);
v19 = a1_pData_Src[v17+1] * a10_pData_Unknow[v18 + 1]; // 加上小数位的精度
v20 = (v19 + a10_pData_Unknow[v18] * a1_pData_Src[v17] + 0x2000) >> 14; //0x2000右移14位为0.5,这里是为了4舍5入;
a2_pData_Dst[j] = v20&0xff;;
}
a2_pData_Dst += dstStepValue;
a1_pData_Src += srcStepValue;
}
}
}
void ImageScale::VerticalScale(byte *a1_pData_Src,int nChannels)
{
byte * pbTmp1;
int nTmp2,nTmp3,nTmp4;
int step,index3;
if(nChannels==4)
{
step=(a8_nWidthScrible<<2);
index1=nChannels*a7_nWidth;
for (int i=0;i<a3_nHeight;i++)
{
pbTmp1= &a1_pData_Src[index1*a5_pData_Unknow[i]];
nTmp2 = a10_pData_Unknow[a6_pData_Unknow[i]<<1];
nTmp3 = a10_pData_Unknow[(a6_pData_Unknow[i]<<1) + 1];
for (int j=0;j<a4_nWidth;j++)
{
index2=((a7_nWidth+j)<<2);
index3=(j<<2);
//blue通道
nTmp4 = (nTmp3 * pbTmp1[index2+MT_BLUE] +nTmp2 * pbTmp1[index3+MT_BLUE] + 0x2000)>>14;
a2_pData_Dst[index3+MT_BLUE] = nTmp4&0xff;
//green通道
nTmp4 = (nTmp3 * pbTmp1[index2+MT_GREEN] +nTmp2 * pbTmp1[index3+MT_GREEN] + 0x2000)>>14;
a2_pData_Dst[index3+MT_GREEN] = nTmp4&0xff;
//red通道
nTmp4 = (nTmp3 * pbTmp1[index2+MT_RED] +nTmp2 * pbTmp1[index3+MT_RED] + 0x2000)>>14;
a2_pData_Dst[index3+MT_RED] = nTmp4&0xff;
a2_pData_Dst[index3+MT_ALPHA] = 255;
}
a2_pData_Dst += step;
}
}
else
{
for (int i=0;i<a3_nHeight;i++)
{
pbTmp1= &a1_pData_Src[a7_nWidth*a5_pData_Unknow[i]];
nTmp2 = a10_pData_Unknow[a6_pData_Unknow[i]<<1];
nTmp3 = a10_pData_Unknow[(a6_pData_Unknow[i]<<1) + 1];
for (int j=0;j<a4_nWidth;j++)
{
nTmp4 = (nTmp3 * pbTmp1[a7_nWidth+j] +nTmp2 * pbTmp1[j] + 0x2000)>>14;
a2_pData_Dst[j] = nTmp4&0xff;
}
a2_pData_Dst += a8_nWidthScrible;
}
}
}
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |