c - 位图缩放同时保持居中

标签 c image algorithm coordinates

我正在嵌入式系统 (stm32f4) 上开发一个支持多点触控的图像查看器。要进行透视,图像查看器应该具有与您在智能手机上找到的功能类似的功能。 我已经完成了图像缩放和捏/缩放手势识别部分。但它仅从源图像原点坐标缩放。因此,如果我的 origin(x,y[0, 0]) 位于左上角,那么它将沿着该点缩放。如果我想在右下角向上看一些东西,我必须使用捏手势和移动到我想要的位置,这是不可取的。这是它的样子 http://i.imgur.com/IWR4wls.gifv .它应该遵循 2 个手指的中心。

如何在跟随 2 个手指的中心的同时实现缩放?我尝试这样做的结果是工作正常但不稳定、摇摇欲坠的版本基本上无法使用。

我的缩放工作原理是让源图像始终打开(在 ram 中)获取源图像 [x,y] 坐标和矩形我想缩放 [w,h] 缩放矩形以显示 [w,h] 并显示它。移动(平移手势)是通过移动源图像中的 zoomRect [x,y] 坐标来完成的。这意味着每次我移动手指时,我都必须移动 zoomedRect(增加 [x,y])缩放 zoomedRect 并显示它。由于内存有限,因此未存储完全缩放的图像。

Source image width,height[640, 480]:
+-------------------------------+
|   zoomedRect                  |
|   +--------------+            |
|   |              |            |
|   |              |            |
|   |              |            |
|   |              |            |
|   |              |            |
|   +--------------+            |
|                               |
|                               |
|                               |
+-------------------------------+

I take zoomedRect i.e. x,y[50, 50] width,height[160, 120]
and scale it to display size w,h[640x480]
Display:
+-------------------------------+
|                               |
|                               |
|                               |
|                               |
|                               |
|                               |
|                               |
|                               |
|                               |
+-------------------------------+

这是我有/可以计算的:

  1. 两根手指的中心。

  2. 将 2 个手指的中心转换为源图像(即使在放大时)。

  3. 按比例缩放 (1.32, 1.45...) 和(源图像宽度|高度)/(zoomedRect 宽度|高度)。

编辑:

我曾尝试计算两根手指接触时的中心点,然后使用该中心进行 future 计算,这就是所有跳跃和摇晃发生的原因。但也许我这边有错误,所以我会添加一些相关代码。 正如我之前提到的,我更改了 zoomRect 的宽度和高度以缩放图像

newWidth = tempWidth / scale;
newHeight = tempHeight / scale;

所以在缩放之后我还需要移动到中心附近,我通过计算比例变化来做到这一点 (lastWidth - newWidth)

newSourceX = newSourceX + ((int16_t)lastWidth - newWidth);
newSourceY = newSourceY + ((int16_t)lastHeight - newHeight);

现在我们需要停在两个手指之间的计算中心并且不要越界 [0, 0]:

#define LIMIT(value, min, max) (value < min ? min : (value > max ? max : value))
newSourceX = LIMIT(newSourceX + ((int16_t)lastWidth - newWidth), 0, centerSourceX);
newSourceY = LIMIT(newSourceY + ((int16_t)lastHeight - newHeight), 0, centerSourceY);

到目前为止一切顺利,但它没有正确居中

Calculate center between two fingers on Display and translate to Source.
Because it's fully zoomed out(Source and Display are identical)
centers are also in identical positions.
Display/Source:
+-------------------------------+
|                               |
|                               |
|                               |
|                               |
|                               |
|                centerPos      |
|                     *         |
|                               |
|                               |
+-------------------------------+

So if we zoom in zoomRect will be newWidth / 2 and newHeight / 2 further than needed.

Source:
+-------------------------------+
|                               |
|                               |
|                               |
|                               |
|                               |
|                centerPos      |
|                     *---------+
|                     | zoomRect|
|                     |         |
+---------------------+---------+

To account for this I modify code as follows:
newSourceX = LIMIT(newSourceX + ((int16_t)lastWidth - newWidth), 0, centerSourceX - newWidth / 2);
newSourceY = LIMIT(newSourceY + ((int16_t)lastHeight - newHeight), 0, centerSourceY - newHeight / 2);

Success!!! Or not?

Source:
+-------------------------------+
|                               |
|                               |
|                               |
|             zoomRect          |
|                +---------+    |
|                |centerPos|    |
|                |     *   |    |
|                +---------+    |  
|                               |
+-------------------------------+

When zooming from 1:1 it works perfectly but when I want to zoom again when
I'm zoomed in a little bit the "jump" happens because:
newSourceX + ((int16_t)lastWidth - newWidth) > centerSourceX - newWidth / 2

结果:http://i.imgur.com/x1t6X2q.gifv

最佳答案

您有源图片,并且源坐标 (x,y) 通过仿射变换转换为屏幕坐标。我假设缩放是统一的。一开始 Scale=1; dx, dy=0

ScrX = (x - dx) * Scale
ScrY = (y - dy) * Scale

因此我们看到了从 dx、dy 点剪切并按缩放倍数扩展的源图像。

dx=1,dy=1, Scale=2 的示例。左侧矩形是源,右侧是屏幕。

enter image description here

让我们开始(b 前缀)放大手指 (bx0, by0)(bx1, by1) 的屏幕位置 - 相反矩形角。结束(或中间)位置(e 前缀)是(ex0, ey0)(ex1, ey1)

让矩形的对角线对应比例尺:

eScale = bScale * Sqrt(((ex1-ex0)^2 + (ey1-ey0)^2) / ((bx1-bx0)^2 + (by1-by0)^2)) 
//use Math.Hypot or Vector.Length if available

所以我们有了新的规模。

我们有开始和结束的中心点

 bcx = (bx0 + bx1) / 2
 bcy = (by0 + by1) / 2
 ecx = (ex0 + ex1) / 2
 ecy = (ey0 + ey1) / 2

这两个屏幕点应该对应同一个源坐标

bcx = (xx - bdx) * bScale
ecx = (xx - edx) * eScale

排除xx我们得到

edx = bdx + bcx / bScale - ecx / eScale

和 edy 的类似公式

所以我们得到了新的移位参数。

关于c - 位图缩放同时保持居中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44967786/

相关文章:

C 链表追加插入

c# - 将日期移动几个月但保持同一天

javascript - 使用类和 ID 在 jquery 中用另一个图像替换图像

html - IE8, FF3 <img> 居中对齐问题

android - 在 Facebook 墙上发布图片和消息时如何完美对齐

java - Java中Levenshtein算法的问题

python - NumPy IFFT 在 OaA 卷积算法中引入黑条

使用gcc和Matlab在mac上编译openmp

c - 将字符附加到字符串

html - 如何将c文件转换为cgi文件?