首页 > 解决方案 > 裁剪和调整大小后如何翻译图像上的点?

问题描述

我正在创建一个程序,它允许用户用点注释图像。该程序允许用户放大图像,以便用户可以更精确地注释。

程序放大图像,执行以下操作:

  1. 找到图像的中心
  2. 查找新裁剪图像相对于中心的最小和最大坐标
  3. 裁剪图像
  4. 将图像调整为原始大小

为此,我编写了以下 Python 代码:

import cv2
def zoom_image(original_image, cut_off_percentage, list_of_points):
    height, width = original_image.shape[:2]
    center_x, center_y = int(width/2), int(height/2)
    half_new_width = center_x - int(center_x * cut_off_percentage)
    half_new_height = center_y - int(center_y * cut_off_percentage)
    min_x, max_x = center_x - half_new_width, center_x + half_new_width
    min_y, max_y = center_y - half_new_height, center_y + half_new_height

     #I want to include max coordinates in new image, hence +1
    cropped = original_image[min_y:max_y+1, min_x:max_x+1]
    new_height, new_width = cropped.shape[:2]

    resized = cv2.resize(cropped, (width, height))
    translate_points(list_of_points, height, width, new_height, new_width, min_x, min_y)

我想将图像调整为原始宽度和高度,以便用户始终在相同的“表面”上工作,无论图像的缩放程度如何。

我遇到的问题是如何在执行此操作时正确缩放点(注释)。我这样做的算法如下:

  1. min_x通过从 x 坐标和min_yy 坐标中减去来平移原始图像上的点
  2. 计算用于缩放点的 x 和 y 坐标的常数
  3. 将坐标乘以常数

为此,我使用以下 Python 代码:

import cv2
def translate_points(list_of_points, height, width, new_height, new_width, min_x, min_y):
    #Calculate constants for scaling points
    scale_x, scale_y = width / new_width, height / new_height

    #Translate and scale points
    for point in list_of_points:
        point.x = (point.x - min_x) * scale_x
        point.y = (point.y - min_y) * scale_y

此代码不起作用。如果我放大一次,很难检测到像素的偏移,但它会发生。如果我继续放大,检测点的“漂移”会容易得多。以下是提供示例的图像。在原始图像 (1440x850) 上,我将一个点放在蓝色十字准线的中间。我放大图像越多,就越容易看到该算法不适用于更大的剪切。

原始图像。蓝色十字准线是图像的中点。红角表示图像缩放一次后的边界

放大一次后的图像。

放大5倍后的图像。显然,绿点不再位于图像中间

我使用的cut_off_percentage是 15%(意味着我保留了原始图像宽度和高度的 85%,从中心计算)。

我还尝试了以下库:Augmentit python library Library 具有裁剪图像和调整它们与点一起调整大小的功能。库也会导致点漂移。这是意料之中的,因为我实现的代码和库的函数使用相同的算法。

此外,我检查了这是否是一个舍入问题。它不是库在将坐标与比例相乘后对点进行四舍五入。无论它们如何四舍五入,点仍然相差 4-5 px。这增加了我放大图片的次数。

编辑:这里给出了更详细的解释,因为我不明白给定的答案。

以下是右手的图像。

我的程序中的一只手的图像

此图像的原始尺寸为宽 1440 像素,高 850 像素。正如您在这张图片中看到的,我在位置 (756.0, 685.0) 处标注了右手腕。为了检查我的程序是否正常工作,我在 GIMP 中打开了这个精确的图像,并在位置 (756.0, 685.0) 放置了一个白点。结果如下:

GIMP 中的手的图像

程序中的坐标正常工作。现在,如果我要根据第一个答案中给出的代码计算第一个答案中给出的参数,我会得到以下信息:

vec = [756, 685] hh = 425 hw = 720 cov = [720, 425]

这些参数对我来说很有意义。现在我想将图像缩放到 1.15 的比例。我通过选择中心点和计算值来裁剪图像,low这些high值指示要保留的图像矩形和要剪切的内容。在下图中,您可以看到切割后保留的内容(红色矩形内的所有内容)。

切割时保留什么

切割时的低点和高点是: xb = [95,1349] yb = [56,794]

裁剪图像尺寸:1254 x 738

裁剪后的图像将被调整回原始图像。但是,当我这样做时,我的注释在使用上述参数时会得到完全错误的坐标。

缩放后

这是我用来根据第一个答案裁剪、调整大小和重新调整点的代码:

width, height = image.shape[:2]
center_x, center_y = int(width / 2), int(height / 2)
scale = 1.15
scaled_width = int(center_x / scale)
scaled_height = int(center_y / scale)
xlow = center_x - scaled_width
xhigh = center_x + scaled_width
ylow = center_y - scaled_height
yhigh = center_y + scaled_height
xb = [xlow, xhigh]
yb = [ylow, yhigh]
cropped = image[yb[0]:yb[1], xb[0]:xb[1]]
resized = cv2.resize(cropped, (width, height), cv2.INTER_CUBIC)

#Rescaling poitns
cov = (width / 2, height / 2)
width, height = resized.shape[:2]
hw = width / 2
hh = height / 2
for point in points:
    x, y = point.scx, point.scy
    x -= xlow
    y -= ylow
    x -= cov[0] - (hw / scale)
    y -= cov[1] - (hh / scale)
    x *= scale
    y *= scale
    x = int(x)
    y = int(y)
    point.set_coordinates(x, y)

标签: python-3.ximageopencvimage-processing

解决方案


我查看了我的代码并意识到我在哪里犯了导致点偏移的错误。

在我的程序中,我有一个特定大小的画布。画布的大小是一个常数,并且总是大于在画布上绘制的图像。当程序在画布上绘制图像时,它首先调整该图像的大小以使其适合画布。调整大小的图像的大小比画布的大小略小。图像通常从画布的左上角开始绘制。因为我想总是在画布的中心绘制图像,所以我将位置从画布的左上角转移到了另一个点。这是我在进行图像缩放时没有考虑到的。

def zoom(image, ratio, points, canvas_off_x, canvas_off_y):
    width, height = image.shape[:2]
    new_width, new_height = int(ratio * width), int(ratio * height)
    center_x, center_y = int(new_width / 2), int(new_height / 2)
    radius_x, radius_y = int(width / 2), int(height / 2)
    min_x, max_x = center_x - radius_x, center_x + radius_x
    min_y, max_y = center_y - radius_y, center_y + radius_y
    img_resized = cv2.resize(image, (new_width,new_height), interpolation=cv2.INTER_LINEAR)   
    img_cropped = img_resized[min_y:max_y+1, min_x:max_x+1]
    for point in points:
        x, y = point.get_original_coordinates()
        x -= canvas_off_x
        y -= canvas_off_y
        x = int((x * ratio) - min_x + canvas_off_x)
        y = int((y * ratio) - min_y + canvas_off_y)
        point.set_scaled_coordinates(x, y)

在下面的代码中canvas_off_xcanvas_off_y是从画布左上角偏移的位置


推荐阅读