挑战图像高手,如何实现BMP的缩放? 我说的位图缩放是指将一个位图文件first.bmp,按比例n缩放后存入第二个位图文件second.bmp,如n=0.5,second.bmp的大小是原来first.bmp的一半。不是使用StretchBlt实现缩放显示!请高手指点! 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 如果是要缩放算法的话,可以用图形的四点转正来做,然后再用双线性插值http://expert.csdn.net/Expert/topic/2077/2077097.xml?temp=.140423这里有讲。 这属于最基本的图像变换处理了,基本思路是遍历目标图的每一个像素点,根据比例因子去计算该点在源图是哪一点,将那一点的像素值存入目标图就行了。伪代码:缩放比率:n目标图:pDst,nDstW(=nSrcW*n),nDstH(=nSrcH*n)原图:pSrc,nSrcW,nSrcHfor(int j; j<nDstH; j++) for(int i; i<nDstW; i++) { pDst = f(pSrc); pDst++; }至于目标图到源图的对应关系f,我想你应该可以自己推出来了吧。 这里有一个处理图形的库啦,你可以研究一下,添加不超过十行代码,应该就能完成你的功能http://www.vchelp.net/vchelp/file2002_4/flib.asp?type_id=18&class_id=1&cata_id=12&article_id=907 CxImagewww.codeproject.com-------------- May you succeed! ------------------- 上面都是高手在论道,都是自己写的算法,小弟是个新人,也发表一下愚见。StretchBlt是可以实现缩放的,为什么不用它把一个BMP用StretchBlt到一个内存DC中呢,然后再DDBTODIB不就可以了。不过这个不是算法了,博大家一笑而已 如果你是想学习的话,就不应该嫌它难。况且我说过,这还只是图像处理的最基本简单的东西。就是这个简单的缩放变换,也还有可扩展的地方,比如你想得到更好的画质,要用到二次线性插值。得到非常完美的画质,要用到高阶插值。当然,如果你要只想简单的得到这样一个效果,用StretchBlt完全可以达到同样的目的。只不过你要StretchBlt到一个MemDC,然后Bitblt回源DC,这样就得到了新的被缩放过的位图。你保存的话,一定是新的位图。 最基本的就是填充或者提取像素: CShowDibDoc* pDoc = GetDocument(); int horizon; int vertical; CScale dlg; //读取放大或者缩小的比例 if(dlg.DoModal()==IDOK) { horizon = dlg.m_horizon; vertical = dlg.m_vertical; } else { return ; } LPBITMAPINFOHEADER lpbmi; //BYTE* lpDIBBits; lpbmi = (LPBITMAPINFOHEADER)GlobalLock((HGLOBAL)pDoc->m_Dib.m_hDIB); LPSTR lpDIB; lpDIB = (LPSTR)GlobalLock((HGLOBAL) pDoc->m_Dib.m_hDIB); unsigned char* lpDIBBits = (unsigned char *)::FindDIBBits(lpDIB); //lpDIBBits = (BYTE*)(lpbmi + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256); HANDLE buffer; LPSTR bufdata; //分配一块内存,用来存放信息头和调色板 buffer = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, sizeof(BITMAPINFO) + 256*sizeof(RGBQUAD)); bufdata = (LPSTR) GlobalLock((HGLOBAL) buffer); //将信息头和调色板暂时存放在刚分配的内存中 for(int k=0; k<sizeof(BITMAPINFO) + 256*sizeof(RGBQUAD); k++) { *(bufdata + k) = *(lpDIB + k); } HANDLE datahandle; LPSTR data; int height = lpbmi->biHeight; int width = lpbmi->biWidth; int lWidthBytes = WIDTHBYTES(width*8); //取出图像中原来的数据 datahandle = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, height*lWidthBytes); data = (LPSTR) GlobalLock((HGLOBAL) datahandle); for(int i=0; i<height; i++) { for(int j=0; j<width; j++) { *(data + i*lWidthBytes + j) = *(lpDIBBits + i*lWidthBytes + j); } } int Sheight = height*vertical/100; //缩小后的图像 int Swidth = width*horizon/100; int lwidthbytes = WIDTHBYTES(Swidth*8);//缩小后的 //释放掉原来的内存快,重新分配内存。 GlobalUnlock((HGLOBAL) pDoc->m_Dib.m_hDIB); GlobalFree((HGLOBAL) pDoc->m_Dib.m_hDIB); pDoc->m_Dib.m_hDIB = (HDIB)GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, sizeof(BITMAPINFO) + 256*sizeof(RGBQUAD) + Sheight*lwidthbytes); lpDIB = (LPSTR)GlobalLock((HGLOBAL) pDoc->m_Dib.m_hDIB); //将暂存的信息头和调色板重新放到新的内存中。 for(int l=0; l<sizeof(BITMAPINFO) + 256*sizeof(RGBQUAD); l++) { *(lpDIB + l) = *(bufdata + l); } //调整信息头 lpbmi = (LPBITMAPINFOHEADER)GlobalLock((HGLOBAL)pDoc->m_Dib.m_hDIB); lpbmi->biSizeImage = (lpbmi->biSizeImage*vertical*horizon)/10000; //lpbmi->biSize = lpbmi->biSize - (3*height*width/4); lpbmi->biHeight = Sheight; lpbmi->biWidth = Swidth; lpDIBBits = (unsigned char*)::FindDIBBits(lpDIB); //调整图像, 进行缩放。 for( int a=0; a<Sheight; a++) { for(int b=0; b<Swidth; b++) { *(lpDIBBits + a*lwidthbytes + b) = *(data + (int)(a*100/vertical)*lWidthBytes + (int)(b*100/horizon)); } } pDoc->SetModifiedFlag(TRUE); GlobalUnlock((HGLOBAL) buffer); GlobalFree((HGLOBAL) buffer); GlobalUnlock((HGLOBAL) datahandle); GlobalFree((HGLOBAL) datahandle); GlobalUnlock((HGLOBAL) pDoc->m_Dib.m_hDIB); //OnDoRealize((WPARAM)m_hWnd,0); OnInitialUpdate(); pDoc->UpdateAllViews(NULL); 做socket通讯? 请问操作word中的SetPageWidth函数的用法 VC中如何将一个矩形的长和宽(单位是厘米)转换成以像素为单位 雪地跪求 怎样用 VC 6.0 写 DLL(备注:超级弱智,关于发卡器)在线等 怎样才能得到这片二维投影是有哪些物体投影的!为了不浪费,答出来了才给分 怎么用标签控件CTabCtrl? 请教有关文件保存的问题(急!菜鸟呼唤帮助) ActiveX难题 opencv2.3打开摄像头语句让程序自动退出,怎么解决 关于内存访问 如何使Slider控件和对话框背景一致,也就是自己控制Slider的界面 怎样使导入的bmp文件的背景色是透明??
http://expert.csdn.net/Expert/topic/2077/2077097.xml?temp=.140423
这里有讲。
计算该点在源图是哪一点,将那一点的像素值存入目标图就行了。伪代码:
缩放比率:n
目标图:pDst,nDstW(=nSrcW*n),nDstH(=nSrcH*n)
原图:pSrc,nSrcW,nSrcHfor(int j; j<nDstH; j++)
for(int i; i<nDstW; i++)
{
pDst = f(pSrc);
pDst++;
}至于目标图到源图的对应关系f,我想你应该可以自己推出来了吧。
http://www.vchelp.net/vchelp/file2002_4/flib.asp?type_id=18&class_id=1&cata_id=12&article_id=907
www.codeproject.com--------------
May you succeed!
-------------------
StretchBlt是可以实现缩放的,为什么不用它把一个BMP用StretchBlt到一个内存DC中呢,然后再DDBTODIB不就可以了。
不过这个不是算法了,博大家一笑而已
就是这个简单的缩放变换,也还有可扩展的地方,比如你想得到更好的画质,要用到二次线性插
值。得到非常完美的画质,要用到高阶插值。当然,如果你要只想简单的得到这样一个效果,用StretchBlt完全可以达到同样的目的。只不过
你要StretchBlt到一个MemDC,然后Bitblt回源DC,这样就得到了新的被缩放过的位图。你保存
的话,一定是新的位图。
CShowDibDoc* pDoc = GetDocument();
int horizon; int vertical; CScale dlg;
//读取放大或者缩小的比例
if(dlg.DoModal()==IDOK)
{
horizon = dlg.m_horizon;
vertical = dlg.m_vertical;
}
else
{
return ;
} LPBITMAPINFOHEADER lpbmi; //BYTE* lpDIBBits; lpbmi = (LPBITMAPINFOHEADER)GlobalLock((HGLOBAL)pDoc->m_Dib.m_hDIB); LPSTR lpDIB; lpDIB = (LPSTR)GlobalLock((HGLOBAL) pDoc->m_Dib.m_hDIB); unsigned char* lpDIBBits = (unsigned char *)::FindDIBBits(lpDIB); //lpDIBBits = (BYTE*)(lpbmi + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256); HANDLE buffer; LPSTR bufdata;
//分配一块内存,用来存放信息头和调色板
buffer = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, sizeof(BITMAPINFO) + 256*sizeof(RGBQUAD)); bufdata = (LPSTR) GlobalLock((HGLOBAL) buffer);
//将信息头和调色板暂时存放在刚分配的内存中
for(int k=0; k<sizeof(BITMAPINFO) + 256*sizeof(RGBQUAD); k++)
{
*(bufdata + k) = *(lpDIB + k);
} HANDLE datahandle; LPSTR data; int height = lpbmi->biHeight; int width = lpbmi->biWidth; int lWidthBytes = WIDTHBYTES(width*8);
//取出图像中原来的数据
datahandle = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, height*lWidthBytes); data = (LPSTR) GlobalLock((HGLOBAL) datahandle); for(int i=0; i<height; i++)
{
for(int j=0; j<width; j++)
{
*(data + i*lWidthBytes + j) = *(lpDIBBits + i*lWidthBytes + j);
}
}
int Sheight = height*vertical/100; //缩小后的图像
int Swidth = width*horizon/100;
int lwidthbytes = WIDTHBYTES(Swidth*8);//缩小后的
//释放掉原来的内存快,重新分配内存。
GlobalUnlock((HGLOBAL) pDoc->m_Dib.m_hDIB); GlobalFree((HGLOBAL) pDoc->m_Dib.m_hDIB); pDoc->m_Dib.m_hDIB = (HDIB)GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, sizeof(BITMAPINFO) + 256*sizeof(RGBQUAD) + Sheight*lwidthbytes);
lpDIB = (LPSTR)GlobalLock((HGLOBAL) pDoc->m_Dib.m_hDIB);
//将暂存的信息头和调色板重新放到新的内存中。
for(int l=0; l<sizeof(BITMAPINFO) + 256*sizeof(RGBQUAD); l++)
{
*(lpDIB + l) = *(bufdata + l);
}
//调整信息头
lpbmi = (LPBITMAPINFOHEADER)GlobalLock((HGLOBAL)pDoc->m_Dib.m_hDIB); lpbmi->biSizeImage = (lpbmi->biSizeImage*vertical*horizon)/10000; //lpbmi->biSize = lpbmi->biSize - (3*height*width/4); lpbmi->biHeight = Sheight; lpbmi->biWidth = Swidth; lpDIBBits = (unsigned char*)::FindDIBBits(lpDIB);
//调整图像, 进行缩放。
for( int a=0; a<Sheight; a++)
{
for(int b=0; b<Swidth; b++)
{
*(lpDIBBits + a*lwidthbytes + b) = *(data + (int)(a*100/vertical)*lWidthBytes + (int)(b*100/horizon));
}
}
pDoc->SetModifiedFlag(TRUE); GlobalUnlock((HGLOBAL) buffer); GlobalFree((HGLOBAL) buffer); GlobalUnlock((HGLOBAL) datahandle); GlobalFree((HGLOBAL) datahandle); GlobalUnlock((HGLOBAL) pDoc->m_Dib.m_hDIB);
//OnDoRealize((WPARAM)m_hWnd,0); OnInitialUpdate(); pDoc->UpdateAllViews(NULL);