首页 > 解决方案 > 如何在 cv2.resize 中找到像素映射到的位置?

问题描述

我想知道,考虑到用于使用 cv2.resize 调整图像大小的插值类型。我怎样才能准确地找出特定像素映射的位置?例如,如果我使用 Linear_interpolation 增加图像的大小并且我为特定像素获取坐标 (785, 251),无论源图像和调整大小的图像之间的纵横比是否发生变化,我怎么能找到在调整大小的版本中,与坐标 == (785, 251) 映射的源图像中的像素到底是什么坐标?我已经在互联网上查看了解决方案,但所有解决方案似乎都是间接方法来找出实际上不适用于不同纵横比的像素图:

https://answers.opencv.org/question/209827/resize-and-remap/

用cv2调整图像大小后,如何获取新的边界框坐标

有没有办法通过 cv2 访问像素的映射方式,并通过反转脚本找出新的坐标?

我想要这样做的原因是,我希望能够创建边界框,无论给定图像的纵横比如何变化,都能给我返回相同的信息。到目前为止,我使用的每种方法都没有给我相同的信息。我想如果我能弄清楚 x,y 左上角和右下角的特定像素坐标映射的位置,我可以重新创建一个准确的边界框,而不管纵横比如何变化。

标签: pythonnumpyopencvimage-resizingcv2

解决方案


当中心坐标为(0, 0)时,缩放坐标有效。

您可以计算x_scaledy_scaled如下:

  • 从和中减去x_original_center和。 减法后,(0, 0) 就是“新中心”。y_original_centerx_originaly_original
  • scale_x通过和缩放“零中心”坐标scale_y
  • x_scaled_center通过添加和将“缩放的零中心”坐标转换为“左上角 (0, 0)” y_scaled_center

准确计算中心:
Python转换为:
(0, 0)为左上角,(cols-1, rows-1)为右下角坐标。
准确的中心坐标为:
x_original_center = (original_rows-1)/2
y_original_center = (original_cols-1)/2


Python代码(假设img是原图):

resized_img = cv2.resize(img, [int(cols*scale_x), int(rows*scale_y)])

rows, cols = img.shape[0:2]
resized_rows, resized_cols = resized_img.shape[0:2]

x_original_center = (cols-1) / 2
y_original_center = (rows-1) / 2

x_scaled_center = (resized_cols-1) / 2
y_scaled_center = (resized_rows-1) / 2

# Subtract the center, scale, and add the "scaled center".
x_scaled = (x_original - x_original_center)*scale_x + x_scaled_center
y_scaled = (y_original - y_original_center)*scale_y + y_scaled_center

测试

以下代码示例在几个原始坐标和缩放坐标处绘制十字:

import cv2

def draw_cross(im, x, y, use_color=False):
    """ Draw a cross with center (x,y) - cross is two rows and two columns """
    x = int(round(x - 0.5))
    y = int(round(y - 0.5))
    if use_color:
        im[y-4:y+6, x] = [0, 0, 255]
        im[y-4:y+6, x+1] = [255, 0, 0]
        im[y, x-4:x+6] = [0, 0, 255]
        im[y+1, x-4:x+6] = [255, 0, 0]
    else:
        im[y-4:y+6, x] = 0
        im[y-4:y+6, x+1] = 255
        im[y, x-4:x+6] = 0
        im[y+1, x-4:x+6] = 255


img = cv2.imread('graf.png')  # http://man.hubwiz.com/docset/OpenCV.docset/Contents/Resources/Documents/db/d70/tutorial_akaze_matching.html
rows, cols = img.shape[0:2]  # cols = 320, rows = 256

# 3 points for testing:
x0_original, y0_original = cols//2-0.5, rows//2-0.5  # 159.5, 127.5
x1_original, y1_original = cols//5-0.5, rows//4-0.5  # 63.5, 63.5
x2_original, y2_original = (cols//5)*3+20-0.5, (rows//4)*3+30-0.5  # 211.5, 221.5
draw_cross(img, x0_original, y0_original)  # Center of cross (159.5, 127.5)
draw_cross(img, x1_original, y1_original)
draw_cross(img, x2_original, y2_original)

scale_x = 2.5
scale_y = 2

resized_img = cv2.resize(img, [int(cols*scale_x), int(rows*scale_y)], interpolation=cv2.INTER_NEAREST)
resized_rows, resized_cols = resized_img.shape[0:2]  # cols = 800, rows = 512

# Compute center column and center row
x_original_center = (cols-1) / 2  # 159.5
y_original_center = (rows-1) / 2  # 127.5

# Compute center of resized image
x_scaled_center = (resized_cols-1) / 2  # 399.5
y_scaled_center = (resized_rows-1) / 2  # 255.5

# Compute the destination coordinates after resize
x0_scaled = (x0_original - x_original_center)*scale_x + x_scaled_center  # 399.5
y0_scaled = (y0_original - y_original_center)*scale_y + y_scaled_center  # 255.5

x1_scaled = (x1_original - x_original_center)*scale_x + x_scaled_center  # 159.5
y1_scaled = (y1_original - y_original_center)*scale_y + y_scaled_center  # 127.5

x2_scaled = (x2_original - x_original_center)*scale_x + x_scaled_center  # 529.5
y2_scaled = (y2_original - y_original_center)*scale_y + y_scaled_center  # 443.5

# Draw crosses on resized image
draw_cross(resized_img, x0_scaled, y0_scaled, True)
draw_cross(resized_img, x1_scaled, y1_scaled, True)
draw_cross(resized_img, x2_scaled, y2_scaled, True)

cv2.imshow('img', img)
cv2.imshow('resized_img', resized_img)
cv2.waitKey()
cv2.destroyAllWindows()

原图:
在此处输入图像描述

调整大小的图像:
在此处输入图像描述

确保十字对齐:
在此处输入图像描述


注意:
在我的回答中,我使用了 Miki 评论的命名约定。


推荐阅读