图片浏览器开发日志-01

按:笔者因为各种原因,已经赋闲在家,为了防止脑袋生锈,决定继续各种学习和提高。目前想编写一个MFC版本的图片浏览器,功能类似光影魔术手的光影看看。Java版本的已经在2017年写完,但是运行不够流畅,因此决定移植到MFC上面。目前基本模块已经移植完成,剩下的就是组装了。本文的目的,一是防止自己遗忘的技术细节,一是抛砖引玉,希望和大家共同学习进步。

以已知点为中心的缩放算法推导

场景:
将图片显示到一个窗口上,在该图片上滚动鼠标滚轮可以对图片进行缩放,同时鼠标所在点不能移动。
请看下图:
图片显示示意图
说明:外面的矩形是要显示图像的映射几何图形,里面的绿色矩形是对应window上的图像显示区域(注意是显示区域,不是所在的控件)。

问题分析:图像缩放的具体技术描述
图像放大,在计算机中就是取出图像中的一部分区域,将该区域显示在固定大小的屏幕上,或者窗口中。截取区域越小,放的比例越大。因此,我们的核心问题就是如何截取这个区域。在本问题中,就是如何确定截取区域的左上矩形的坐标以及矩形的长和宽。

我们建立以A0为原点的平面直角坐标系,并令P(x,y)为鼠标点所在的点。根据上述分析,我们只需要将A1点的坐标求出来,就可以根据几何比例关系得到需要显示部分的图像区域在原图像中的位置。(说明:A1点的坐标的绝对值就是到A0的水平和垂直距离,这样就相当于求出了内部矩形在外部矩形(图形)中的相对位置)。假设放大比例是R,我们根据P点的坐标,很容易算出A1点的坐标。 为了方便叙述,我们只计算横坐标。
根据放大系数,P点到A1B1的距离是 PxR, 因此A1点的横坐标是
Px-Px
R。这样就得到了A0点到A1B1的距离(图中红线的长度), 为: 0-(Px-PxR)= PxR-Px;
根据比例关系,得到A0对应在原图中的位置(列索引)为
gX =(PxR-Px)/A1D1GW
GW 为原始图像的宽度。
截取图像的区域的宽度就是内部矩形的宽度。
同理可以获得截取区域的行索引和高度。

注意:以上推导是纯数学推导,没有考虑计算机变量类型引起的影响。

代码实现

根据上面推导过程,给出截取函数的代码。
getSubImgFromOrg(CImage & orgImg, float R, CMyRect A1, CPoint P, CRect viewRec, CImage & subImg) {
m_A2.top = P.y - (P.y - A1.top)R ;
m_A2.left = P.x - (P.x - A1.left)R ;
int subImgX, subImgY;
int orgW, orgH;
orgW = orgImg.GetWidth();
orgH = orgImg.GetHeight();
float A2W, A2H;
A2W = A1.Width()R;
A2H = A1.Height()R;
if (A2W
A2H == 0) {
return false;
}
m_A2.right = m_A2.left + A2W;
m_A2.bottom = m_A2.top + A2H;
subImgX = -1.0
m_A2.left / A2W * orgW;
subImgY = -1.0
m_A2.top / A2H * orgH;
int subImgW, subImgH;
subImgW = viewRec.Width() / A2W
orgW;
subImgH = viewRec.Height() / A2HorgH;
CMyImage myImg;
if (subImgW
subImgH > 1 )
{
myImg.getSubImge(orgImg, subImgX, subImgY, subImgW, subImgH, subImg);
return true;
}
return false;
}

说明:上述函数中使用了迭代,其中的A1 是上一次计算的矩形(对应上图中A0),m_A2 是本次计算的矩形区域,该结果将作为下一次调用的输入参数。

小结

本文的目的是记录和整理作者的思路,虽已经尽力去详述,仍然比较粗糙。原理貌似简单,但是实现起来还是有诸多问题。笔者目前已经完成了,图像的缩放和移动,但是代码调试用了将近一周,一度怀疑算法有问题。后来经过仔细跟踪,发现是理论数值计算误差所致。本软件正在开发中,原型将会很快面世。本人将会将开发过程和心得在这里一一记录,如果能饷各位看官也不是一件坏事。谢谢大家阅读。

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

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

猜你喜欢

转载自blog.csdn.net/Uman/article/details/104891296