图片浏览器开发日志-03(图片缩放进一步处理)

引语:图片浏览器,必然要涉及到窗口的缩放,这样才能使用户的体验良好。窗口缩放之后,原来的图像是跟随缩放还是只是画布进行缩放,这是个个人感受问题。笔者经过测试其他软件,发现基本都是跟随缩放的,因此本软件也采用这个模式。另外,鼠标控制图像缩放也是一个必然的场景。本文将给出缩放算法思路以及碰到问题的解决办法。

缩放碰到问题

基本思路:利用微软提供的基本类库和函数实现图像的缩放。
StretchBlt 函数简介。(以下内容来自百度百科)
该函数从源矩形中复制一个位图到目标矩形,必要时按目标设备设置的模式进行图像的拉伸或压缩。
BOOL StretchBlt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc , DWORD dwRop);

参数的具体含义请自行网搜,就不再赘述了。
放大的过程:
放大过程的就是截取原有图像的一部分,然后将该内容显示在比这个区域更大的区域内,就会产生放大的效果,这也好利用StretchBlt 函数。
具体做法:使函数中的划线部分小于函数中的加粗部分,就可以实现放大效果,相反就是缩小的效果。
这样看来,问题就解决了,但是笔者在实际执行过程当中,发现图像放大到一定程度之后,其鼠标定位点会发生跳动。简单分析原因应该是整数误差所致。
如图所示所示的对比,定位点为图像中心,在放大到很大之后,发生偏差:

在这里插入图片描述
在这里插入图片描述
对比着两幅图像,发现中心点出现偏差,视觉效果就是出现图像的抖动,看着很不舒服。
为了解决这个问题,笔者对图像缩小和放大菜采用两种方法。贴的缩小时,采用上述方法,图像放大时,采用从原始图像中截取部分图像再填充到一个大的图像中的方法。结果显示效果良好。当然在缩放代码的转换接部分,还是颇出现了周折,导致图像抖动。

// 下面是代码实现的细节:
// An highlighted block
		if (subImgW <= orgW && subImgH <= orgH)
		{
			myImg.getSubImge(orgImg, subImgX, subImgY, subImgW, subImgH, subImg);// 
			m_Ratio2 = (float)orgImg.GetWidth()/ subImgW;// 避免图像抖动的关键
		}
		else 
		{// if the image is much larger , the CImage.create functon will incur an error which might be a graphic memory error.
			  // Therefor ,we will do something for the original MFC StretchBlt which is used to scale the imgage, see below
			if (!subImg.IsNull()) {
				subImg.Destroy();
			}
			subImg.Create(m_ImgRect.Width(), m_ImgRect.Height(), 24);


			CBilinearZoomFilter bzFilter;
			CImage tmpImg;
			m_Ratio2 *= R;
			CDC* pSrcDC = CDC::FromHandle(orgImg.GetDC());
			CDC* pDstDC = CDC::FromHandle(subImg.GetDC());

			
			int ModeOld = SetStretchBltMode(pDstDC->m_hDC, COLORONCOLOR);//设置指定设备环境中的位图拉伸模式, looks like STRETCH_HALFTONE mode,  0.16 ms or 0.00 ms
			int w, h;
			w = viewRec.Width()*m_Ratio2;
			h = viewRec.Height()*m_Ratio2;
			pDstDC->StretchBlt(m_A2.left+0.5, m_A2.top+0.5, w, h, pSrcDC, 0, 0, orgImg.GetWidth(), orgImg.GetHeight(), SRCCOPY);

			SetStretchBltMode(pDstDC->m_hDC, ModeOld);
			subImg.ReleaseDC();
			orgImg.ReleaseDC();

//
下面是 getSubImge的显示代码

// A code block
getSubImge(CImage &srcImg, int x, int y, int width, int height,CImage &subImg)
{
	//1#create a sub image according the location and size indicated by the parameters 

	//CImage srcBak;
	//srcBak.Create(width, height, 32, CImage::createAlphaChannel);//这样做是为了拷贝数据方便,一个像素四个字节,正好是个整数,整数访问比较方便。 

	if(!subImg.IsNull())
		subImg.Destroy();
	subImg.Create(width, height, 32, CImage::createAlphaChannel);// CImage::createAlphaChannel);// this make the data stored in an int array arranged simple
	//subImg.Create(7625, 9646, 32, CImage::createAlphaChannel);// CImage::createAlphaChannel);// this make the data stored in an int array arranged simple
																 //subImg.Create(width, height, 24,0);// this make the data stored in an int array arranged simple

	CDC* pSrcDC = CDC::FromHandle(srcImg.GetDC());
	CDC* pDstDC = CDC::FromHandle(subImg.GetDC());

	pDstDC->StretchBlt(0, 0, width, height, pSrcDC, x, y, width, height, SRCCOPY);
	
	subImg.ReleaseDC();
	srcImg.ReleaseDC();


}

至此:缩放的奇数细节已经实现,并通过调试了。

开发碰到的问题回顾

应该说图像的缩放和移动的算法是没有问题,但是在开发过程当中碰到了很多图像放大和缩放的很多问题。主要是图像放大和缩小的切换抖动问题,问题如下:
1、整数精度问题
利用整数计算,系统会舍掉小数部分,在放大或者缩小比例悬殊时,出现较大误差;
2、数学模型和代码对应没有不完整,这主要是思路不清所致;
3、C++图像处理函数不熟悉,导致理解障碍。
4、显示速度比较慢,切换图像有延时。这个问题利用多线程进行了处理,提前将图片载入内存,使问题得以解决。

下一步:将读取相机信息。

2020-3-23 于北京海淀泛五道口地区。

发布了7 篇原创文章 · 获赞 0 · 访问量 238

猜你喜欢

转载自blog.csdn.net/Uman/article/details/105041980
今日推荐