如何在 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 中将二进制图像的内容/对象居中?的主要内容,如果未能解决你的问题,请参考以下文章