导航
  • 主页
  • VC综合技术
  • 互联网技术
  • MFC AppLauncher
  • .NET 技术
  • 界面
  • 进程
  • 算法
  • 硬件/系统
  • 数据库
  • VC++技术资源

请问已得到一个图象的数据,怎么进行变小?

daipig 2009-08-10 10:40:24
我得到1280*800的图象,用StretchDIBits函数和BitBlt进行显示的,
我想把它变成800*600的图象,请问该怎么做?

大哥大姐帮帮忙...
...全文
171 点赞 收藏 32
写回复
32 条回复
切换为时间正序
请发表友善的回复…
发表回复
daipig 2009-08-12
谢谢大家了 是我搞错了StretchDIBits函数的真正意思,这个图象是分成块来发的,我没弄清楚
回复
LPR_Pro 2009-08-12
/// 这是一个三次样条插值函数,获得每个像素点的值,一个800*600的话,采用循环即可实现
unsigned char Interpolate(unsigned char *lpbySrcXY, int x, int y,
double fu, double fv, int nScanWidth, int nScanHeight, int nBytesPerPixel/*=1*/)
{
// 返回值
unsigned char ucharReturn;
// 循环变量
int i, j;
//像素坐标
int xx[4], yy[4];
//相邻四个像素的像素值
BYTE abyRed[4][4];

xx[0] = -1; xx[1] = 0; xx[2] = 1; xx[3] = 2;
yy[0] = -1; yy[1] = 0; yy[2] = 1; yy[3] = 2;

//保证合法
if((x - 1) < 0) xx[0] = 0;
if((x + 1) > (nScanWidth - 1)) xx[2] = 0;
if((x + 2) > (nScanWidth - 1)) xx[3] = ((xx[2] == 0) ? 0 : 1);

if((y - 1) < 0) yy[0] = 0;
if((y + 1) > (nScanHeight - 1)) yy[2] = 0;
if((y + 2) > (nScanHeight - 1)) yy[3] = ((yy[2] == 0) ? 0 : 1);

//像素点(x, y)的数据位置
//获取数据
for( i= 0; i< 4; i++)
{
//像素点(x, y)的数据位置
BYTE* pbySrcBase = lpbySrcXY + yy[i] * nScanWidth * nBytesPerPixel;

for( j = 0; j< 4; j++)
{
BYTE* pbySrc = pbySrcBase + xx[j]*nBytesPerPixel;
abyRed[i][j] = *pbySrc;
}
}

//u, v向量
double afu[4], afv[4];

afu[0] = Sinxx(1.0f + fu);
afu[1] = Sinxx(fu);
afu[2] = Sinxx(1.0f - fu);
afu[3] = Sinxx(2.0f - fu);

afv[0] = Sinxx(1.0f + fv);
afv[1] = Sinxx(fv);
afv[2] = Sinxx(1.0f - fv);
afv[3] = Sinxx(2.0f - fv);

//矩阵乘向量的中间值
double afRed[4] = {0.0f, 0.0f, 0.0f, 0.0f};

for( i = 0; i < 4; i++)
{
for( j = 0; j < 4; j++)
{
afRed[i] += afv[j] * abyRed[j][i];
}
}

ucharReturn = (unsigned char )(BOUND((afu[0] * afRed[0] + afu[1] * afRed[1] + afu[2] * afRed[2] +
afu[3] * afRed[3]), 0, 255));

return ucharReturn;
}
回复
LPR_Pro 2009-08-12
// 这只是灰度值的处理,彩色的话,使用三次即可
nWidth, nHeight; // 原始大小
lpData; // 原始图像数据指针
lpDestData; // 目标图象数据指针
int nDestWidth, nDestHeight; // 目标图像大小
int Size = nDestWidth* nDestWidth;


// 按列处理
for(i=0; i<nDestHeight; i++)
{
y = (int)( i * (nHeight-1)/ nDestHeight);
int m = (int)( nDestHeight - i*(nHeight-1)%nDestHeight);
unsigned char * pLinePrev = ( lpData+ y * nWidth);

if( (y+1) < nHeight )
{
unsigned char * pLineNext = ( m == nDestHeight ) ? pLinePrev : (pLinePrev + nWidth);
}
else
{
unsigned char * pLineNext = pLinePrev;
}
// 按行处理
for(j=0; j<nDestWidth; j++)
{
int x1 = (int)( j * (nWidth-1) / nDestWidth);
int x2 = x1+1;
int n = (int)( nDestWidth - j*(nWidth-1)%nDestWidth );
unsigned char pA = *(pLinePrev+x1);
unsigned char pB = *(pLinePrev+x2);
unsigned char pC = *(pLineNext+x1);
unsigned char pD = *(pLineNext+x2);

if( n == nDestWidth )
{
pB = pA;
pD = pC;
}

*(lpDestData+i*nDestWidth+j) = 255 - (unsigned char)((int) (n*m*(pA-pB-pC+pD)
+ nCharWidth * m * pB
+ nCharHeight * n * pC
+ (Size - nCharHeight*n - nCharWidth*m) * pD + Size/2)/Size);
}
}
回复
baoyz 2009-08-12
[Quote=引用 28 楼 saimen 的回复:]
使用GDI+

Graphics graphics(hDC);

CImage image(L"myfile.bmp")...JPG PNG....

graphics.DrawImage(&image,0,0,image.GetWidth(),image.GetHeight(),800,600);

OK.....
[/Quote]
这个最简单。GDI+可以读文件,也可以从流输入。
回复
HuWenjin 2009-08-11
使用GDI+

Graphics graphics(hDC);

CImage image(L"myfile.bmp")...JPG PNG....

graphics.DrawImage(&image,0,0,image.GetWidth(),image.GetHeight(),800,600);

OK.....
回复
副组长 2009-08-10
[Quote=引用 13 楼 daipig 的回复:]
回12楼 貌似显示不全 都到下面去了。
[/Quote]
(LPBITMAPINFO)pBitmapInfo
这个参数指向的结构应该是你源图像的,应该1280*800,你检查一下。
回复
daipig 2009-08-10
[Quote=引用 17 楼 lambochan 的回复:]
引用 14 楼 daipig 的回复:
虽然图象是1280*800的,但是得到的图象头的数据如下:
biSize = 40
biWide = 160
biHeight = 200
biPlanes = 1
biBitCount = 4
biSizeImage = 16000



咳....这个... 4Bit的,160 x 200 pixel?
还要将它过度拉伸成800x600,而且长宽比例还要反转..

一,首先就会变形失真.
二,由于只有16色..恐怕用GDI缩放会死很惨..
[/Quote]
正常显示无问题 这个数据是1280*800的 正常的话没问题
回复
雪影 2009-08-10
[Quote=引用 13 楼 daipig 的回复:]
回12楼 貌似显示不全 都到下面去了。
[/Quote]
你查看一下参数有无设置争取。

图像缩放
GDI使用StretchDIBits
GDI+使用Image::DrawImage
回复
lambochan 2009-08-10
[Quote=引用 14 楼 daipig 的回复:]
虽然图象是1280*800的,但是得到的图象头的数据如下:
biSize = 40
biWide = 160
biHeight = 200
biPlanes = 1
biBitCount = 4
biSizeImage = 16000
[/Quote]


咳....这个... 4Bit的,160 x 200 pixel?
还要将它过度拉伸成800x600,而且长宽比例还要反转..

一,首先就会变形失真.
二,由于只有16色..恐怕用GDI缩放会死很惨..
回复
huziwu 2009-08-10
直接使用StretchDIBits得到的效果很差
在使用前先SetStretchBltMode(dc,STRETCH_DELETESCANS);//加上这句图像效果会好很多
不过可以自己写算法实现,直接对数据进行缩放或拉伸,以下是我以前写过的代码,效果还不错:
void StretchBuf(BYTE *sBuf,int sw,int sh,BYTE *dBuf,int dw,int dh,int ByteCnt)
{
double TimesW = sw*1.0/dw;
double TimesH = sh*1.0/dh;
int m;//纵方向点
int n;//横方向点
double v;//纵方向抽取倍率
double u;//横方向抽取倍率
double PosW,PosH;
for (int i=0;i<dh-1;i++)
{
PosH = i*TimesH;//纵方向抽取点位置
m = (int)PosH;//纵向抽取点位置
v = PosH - (int)PosH;
for (int j=0;j<dw-1;j++)
{
PosW = j*TimesW;//横方向抽取点位置
u = PosW - (int)PosW;
n = (int)PosW;//横向抽取点位置

int x1 = (m*sw+n)*ByteCnt;
int x2 = x1+ByteCnt;
int y1 = ((m+1)*sw+n)*ByteCnt;
int y2 = y1+ByteCnt;
for (int k=0;k<ByteCnt;k++)//按分量抽取,例如32位则有4个分量
{
dBuf[(i*dw+j)*ByteCnt+k] = (BYTE)((1-v)*((1-u)*sBuf[x1+k]+u*sBuf[x2+k])+v*((1-u)*sBuf[y1+k]+u*sBuf[y2+k]));
}
}
}
}
回复
daipig 2009-08-10
虽然图象是1280*800的,但是得到的图象头的数据如下:
biSize = 40
biWide = 160
biHeight = 200
biPlanes = 1
biBitCount = 4
biSizeImage = 16000
回复
daipig 2009-08-10
虽然图象是1280*800的,但是得到的图象头的数据如下:
biSize = 40
biWide = 160
biHeight = 200
biPlanes = 1
biBitCount = 4
biSizeImage = 16000
回复
daipig 2009-08-10
回12楼 貌似显示不全 都到下面去了。
回复
副组长 2009-08-10
只是显示你什么也不用做,在StretchDIBits把参数设置正确就可以了。

::StretchDIBits(pDC->m_hDC, // hDC
rcDest.left, // 你设置 0 这个是开始的位置
rcDest.top, // 0
rcDest.right-rcDest.left, // 目标数据的宽度 你的是 800
rcDest.bottom-rcDest.top, // 高度 600
rcDIB.left, // 0
srcy, // 0
rcDIB.right-rcDIB.left, // 你设 1280
rcDIB.bottom-rcDIB.top, // 800
pBitmapData, // 数据的指针
(LPBITMAPINFO)pBitmapInfo, // 头的指针
DIB_RGB_COLORS, //
SRCCOPY); //
回复
副组长 2009-08-10
如果你想对数据进行真实变换可以这样
如果buf是你的像素的数据,大小是 1280*800*3,24位真彩色数据。
现在变换成 800*600*3
BYTE * buf2 = new BYTE[800*600*3];
for(int i=0; i<600; i++)
{
for(int j=0; j<800; j++)
{
buf2[(i*800+j)*3 + 0] = buf[(((int)(i*1.333))*1280 +((int)(j*1.6))) * 3 + 0];
buf2[(i*800+j)*3 + 1] = buf[(((int)(i*1.333))*1280 +((int)(j*1.6))) * 3 + 1];
buf2[(i*800+j)*3 + 2] = buf[(((int)(i*1.333))*1280 +((int)(j*1.6))) * 3 + 2];
}
}
现在数据就已经是800*600的了,
再把你的BITMAPINFOHEADER的宽度、高度和字节数改掉就可以了。
回复
fly113 2009-08-10
直接调用API肯定会失真的,最好还是用双线性插值等方法生成一个800*600的数据,再放进来显示。
回复
daipig 2009-08-10
[Quote=引用 7 楼 tttyd 的回复:]
楼主是想将1280*800的图象,在800*600的窗口中完全显示?
还是将1280*800的图象文件转换成800*600的图像文件?
如果是后者的话,使用楼上说的方法。
如果是前者,仅仅是显示而已,有很多现成的API可以使用。
[/Quote]
能教下我吗 是前者 只需要显示就可以了 但是一直不得法
回复
daipig 2009-08-10
[Quote=引用 3 楼 fishion 的回复:]
就这几个API来做的话,图像会失真
[/Quote]
我尝试过目标矩形的长宽直接改变,再使用StretchDIBits函数,但是结果显示的图象宽高是没问题了,但是图象严重失真
回复
雪影 2009-08-10
楼主是想将1280*800的图象,在800*600的窗口中完全显示?
还是将1280*800的图象文件转换成800*600的图像文件?
如果是后者的话,使用楼上说的方法。
如果是前者,仅仅是显示而已,有很多现成的API可以使用。
回复
发动态
发帖子
VC/MFC
创建于2007-09-28

1.5w+

社区成员

VC/MFC相关问题讨论
申请成为版主
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……