如何在 python 中将二进制图像的内容/对象居中?

Posted

技术标签:

【中文标题】如何在 python 中将二进制图像的内容/对象居中?【英文标题】:How to center the content/object of a binary image in python? 【发布时间】:2020-04-18 21:26:12 【问题描述】:

我有一个计算图形方向的代码。然后基于这个方向旋转图形直到它被拉直。这一切都很好。我正在努力解决的问题是将旋转图形的中心移到整个图像的中心。所以图形的中心点应该与整个图像的中心点一致。

输入图像:

代码:

import cv2
import numpy as np
import matplotlib.pyplot as plt

path = "inputImage.png"


image=cv2.imread(path)
gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh=cv2.threshold(gray,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]

contours,hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
cnt1 = contours[0]
cnt=cv2.convexHull(contours[0])
angle = cv2.minAreaRect(cnt)[-1]
print("Actual angle is:"+str(angle))
rect = cv2.minAreaRect(cnt)

p=np.array(rect[1])

if p[0] < p[1]:
        print("Angle along the longer side:"+str(rect[-1] + 180))
        act_angle=rect[-1]+180
else:
        print("Angle along the longer side:"+str(rect[-1] + 90))
        act_angle=rect[-1]+90
#act_angle gives the angle of the minAreaRect with the vertical

if act_angle < 90:
        angle = (90 + angle)
        print("angleless than -45")

        # otherwise, just take the inverse of the angle to make
        # it positive
else:
        angle=act_angle-180
        print("grter than 90")

# rotate the image to deskew it
(h, w) = image.shape[:2]
print(h,w)
center = (w // 2, h // 2)
print(center)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
rotated = cv2.warpAffine(image, M, (w, h),flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)

plt.imshow(rotated)
cv2.imwrite("rotated.png", rotated)

有输出:

如您所见,白色图形略微向左放置,我希望它完全居中。 有谁知道如何做到这一点?

编辑:我尝试了@joe 的建议,并通过将图片的宽度和高度除以 2 从图像的中心减去质心坐标。由此我得到了一个偏移量,这个必须添加到描述图像的数组中。但我不知道如何将偏移量添加到数组中。这将如何处理 x 和 y 坐标?

代码:

img = cv2.imread("inputImage")
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray_image,127,255,0)

height, width = gray_image.shape
print(img.shape)
wi=(width/2)
he=(height/2)
print(wi,he)
M = cv2.moments(thresh)

cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])

offsetX = (wi-cX)
offsetY = (he-cY)


print(offsetX,offsetY)
print(cX,cY)

【问题讨论】:

***.com/questions/31400769/… 可以帮助找到非零矩形的中心 使用 numpy.meshgrid 获取具有 x 和 y 坐标的矩阵。然后您可以展平数组并使用docs.scipy.org/doc/numpy-1.9.2/reference/generated/… 创建加权平均值,或者您可以使用许多可用函数之一,例如learnopencv.com/…。知道质心后,您可以从图像的中心像素中减去它以获得偏移量。然后将此偏移量添加到您的数据中。 我知道如何获取质心坐标,但是如何从图像的中心像素中减去这些坐标?这是减去宽度/2 和高度/2 的坐标吗? 我已经尝试过您的建议(请参阅编辑),将偏移量添加到图像数组是我卡住的地方。 【参考方案1】:

这是 Python/OpenCV 中的一种方式。

从轮廓中获取白色区域的边界框。计算重新定位区域的偏移量。使用 numpy 切片将其复制到输入大小的黑色背景的中心。

输入:

import cv2
import numpy as np

# read image as grayscale
img = cv2.imread('white_shape.png', cv2.COLOR_BGR2GRAY)

# get shape
hh, ww = img.shape


# get contours (presumably just one around the nonzero pixels) 
contours = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
for cntr in contours:
    x,y,w,h = cv2.boundingRect(cntr)

# recenter
startx = (ww - w)//2
starty = (hh - h)//2
result = np.zeros_like(img)
result[starty:starty+h,startx:startx+w] = img[y:y+h,x:x+w]

# view result
cv2.imshow("RESULT", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

# save reentered image
cv2.imwrite('white_shape_centered.png',result)

【讨论】:

【参考方案2】:

一种方法是获取二进制对象的边界框坐标,然后使用 Numpy 切片裁剪 ROI。从这里我们计算新的移位坐标,然后将 ROI 粘贴到新的空白蒙版上。

代码

import cv2
import numpy as np

# Load image as grayscale and obtain bounding box coordinates
image = cv2.imread('1.png', 0)
height, width = image.shape
x,y,w,h = cv2.boundingRect(image)

# Create new blank image and shift ROI to new coordinates
mask = np.zeros(image.shape, dtype=np.uint8)
ROI = image[y:y+h, x:x+w]
x = width//2 - ROI.shape[0]//2 
y = height//2 - ROI.shape[1]//2 
mask[y:y+h, x:x+w] = ROI

cv2.imshow('ROI', ROI)
cv2.imshow('mask', mask)
cv2.waitKey()

【讨论】:

这与我在下面已经提出的非常相似。但总是很高兴看到变化。我没有明确裁剪 ROI,而是直接在 numpy 切片中进行了相同的裁剪。【参考方案3】:

@NawinNarain,从这一点开始,您发现了 w.r.t 的相对变化。图像的质心,它非常简单 - 你想用这个翻译制作一个仿射矩阵并将 cv2.warpAffine() 应用于你的图像。就是这样。

T = np.float32([[1, 0, shift_x], [0, 1, shift_y]]) 

然后我们使用 warpAffine() 使用矩阵 T 变换图像

centered_image = cv2.warpAffine(image, T, (orig_width, orig_height))

这将转换您的图像,使质心位于中心。希望这可以帮助。完整的中心图像函数如下所示:

def center_image(image):
  height, width = image.shape
  print(img.shape)
  wi=(width/2)
  he=(height/2)
  print(wi,he)

  ret,thresh = cv2.threshold(image,95,255,0)

  M = cv2.moments(thresh)

  cX = int(M["m10"] / M["m00"])
  cY = int(M["m01"] / M["m00"])

  offsetX = (wi-cX)
  offsetY = (he-cY)
  T = np.float32([[1, 0, offsetX], [0, 1, offsetY]]) 
  centered_image = cv2.warpAffine(image, T, (width, height))

  return centered_image

【讨论】:

以上是关于如何在 python 中将二进制图像的内容/对象居中?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Python 中将字节数转换为二进制数?

如何在reactjs中将数据二进制转换为图像?

如何在Python框架Flask中将图像文件从表单上传到数据库

如何在本机反应中将图像读取为二进制/ blob

如何在 django 中将多个图像一起发布?

如何在 R 中将图像上传到 SQL Server