图片浏览器开发日志-08(简单透视代码的实现)

按:编个小程序是为了度过松弛的业余生活,也是为了维持自己有记忆以来的性格特质:就是总得学点什么干点什么。我写这个图片浏览器,目的无非如此。因为有那么多的免费软件,想如何如何使何其难也。下面开始进行美化,第一步是按钮平面化。本文是平面化过程中碰到的一个小问题,此问题解决后再实现按钮的平面化。

按钮风格设计引发的透视计算问题

我的java版的按钮风格是鼠标移到按钮上面之后,按钮图片形成一个倒下的感觉,本质是一个图片的投影。因此,这涉及到如何完成一个图片的投影变化。因此这两天又上网查了一下资料,发现这个东西要做好了,还挺复杂,要首先计算出投影矩阵(透视矩阵)。是一个八个未知数的线性方程组。遥想当年,自己的数值分析差点儿不及格啊。真是汗颜,虽然印象当中还有什么高斯消去法,牛顿什么迭代法,什么龙格库塔法,但是早已忘得找不着北了。不妨先记下,然后在慢慢理会。

以下来自:https://www.cnblogs.com/faith0217/articles/5027490.html

要点如下:

四顶点校正透视变换的线性方程解

透视变换矩阵的形式为:
在这里插入图片描述
最终变换为:

在这里插入图片描述
ok,解上述方程就可以了。

我准备在我后续的图像编辑软件中将仔细研究上述方法,在本软件中,我将采用一个小trick,解决投影的问题。

我的的变化一个简单的投影,即一个矩形投影为一个等腰梯形,切底和高和矩形的底和高平行,底边不变。
如图示:
在这里插入图片描述

变化分成两步,第一步得到原图的压缩高度的图像,即A’BCD‘’,这个变化很简单。第二步,将压缩后的图像经过变换变成中间的投影,即那个梯形。我的方法如下:
按:实际上A"D"的长度是已知的,或者说是可以设定的。这样利用简单的相似三角形概念,可以依次计算出到底边距离H,对应的EF的长度。可以看出,梯形图像就是一系列EF线的积分,白话说法就是,梯形的图像是由高度为1 的一系列图像叠加而成。这样我们就可以近似得到这个梯形图像了。
代码如下

void CImgShape::perspectiveWindow(CImage &src, int tH, int tTopL, CString dir, CImage &dst) {
    
    
	int src_width = src.GetWidth();
	int src_height = src.GetHeight();
	CImage img1;
	float dstX, dstY, dstW, dstH, srcX, srcY, srcW, srcH;
	int tBotL;

	if (dir == "U" || dir == "D") {
    
    
		dstH = tH;
		dstW = src_width;
	}
	else {
    
    
		dstH = src_height;
		dstW = tH;
	}
	img1.Create(dstW, dstH, 24);
	
	if (!dst.IsNull()) {
    
    
		dst.Destroy();
	}
	dst.Create(img1.GetWidth(), img1.GetHeight(), 24);
	CDC* pSrc0DC = CDC::FromHandle(src.GetDC());
	CDC* pSrc1DC = CDC::FromHandle(img1.GetDC());


	CDC* pDstDC = CDC::FromHandle(dst.GetDC());


	int ModeOld = SetStretchBltMode(pSrc1DC->m_hDC, COLORONCOLOR);//设置指定设备环境中的位图拉伸模式, looks like STRETCH_HALFTONE mode,  0.16 ms or 0.00 ms
	
	//1# get imag1 
	pSrc1DC->StretchBlt(0,0,  dstW, dstH, pSrc0DC, 0,0, src_width, src_height, SRCCOPY);
	SetStretchBltMode(pSrc1DC->m_hDC, ModeOld);
//1# get the dist image
	ModeOld = SetStretchBltMode(pDstDC->m_hDC, COLORONCOLOR);//设置指定设备环境中的位图拉伸模式, looks like STRETCH_HALFTONE mode,  0.16 ms or 0.00 ms

	
	if (dir == "U" || dir == "D") {
    
    
		srcH = 1;
		dstH = 1;
		srcX = 0;
		srcW = src_width;
		tBotL = src_width;
	}
	else {
    
    
		srcW = 1;
		dstW = 1;
		srcY = 0;
		srcH = src_height;
		tBotL = src_height;
	}


	int dL;// the difference of the two parallel edge of the trapezoid
	int L;
	

	for (int h = 0; h < tH;h++)
	{
    
    


		if (dir == "U" ) {
    
    
			srcY = h;
			dstY = srcY;
			dL = (tBotL - tTopL) / 2.0 / tH * h;
			L = tBotL - dL * 2;
			dstW = L;
			dstX = dL;
	
		}else if(dir == "D"){
    
    
			srcY = tH - h;
			dstY = srcY;
			dL = (tBotL - tTopL) / 2.0 / tH * h;
			L = tBotL - dL * 2;
			dstW = L;
			dstX = dL;

		}else if (dir == "L") {
    
    
			srcX = h;
			dstX = srcX;
			dL = (tBotL - tTopL) / 2.0 / tH * h;
			L = tBotL - dL * 2;
			dstH = L;
			dstY = dL;

		}
		else if (dir == "R") {
    
    
			srcX = tH - h;
			dstX = srcX;
			dL = (tBotL - tTopL) / 2.0 / tH * h;
			L = tBotL - dL * 2;
			dstH = L;
			dstY = dL;
		}
		else {
    
    
			throw "Bad parameters...";
		}


		pDstDC->StretchBlt(dstX, dstY, dstW,dstH, pSrc1DC, srcX, srcY, srcW, srcH, SRCCOPY);
	}
	SetStretchBltMode(pDstDC->m_hDC, ModeOld);
	src.ReleaseDC();
	img1.ReleaseDC();
	dst.ReleaseDC();
	return ;
}

调用代码如下:

perspectiveWindow(m_myImg, GetHeight()/1.5,myImg.GetWidth()/2,L"U",dest);

参数说明:
CImage &src:源图像
int tH:变形后梯形的高
int tTopL: 变形后梯形的顶边长度
CString dir: 变化的方向UDLR, 四选一
CImage &dst: 变化后图像
因为支持四种方向的变化,因此程序用了一点小技巧。读者如果有问题可以提问,不再详述。

2020-04-07

猜你喜欢

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