英文:
How to overlay segmentation result with another image?
问题
你想要将分割后的图像中的颜色更改为另一张图像,类似于将分割板(颜色)更改为你的标志/logo。要实现这个目标,你可以使用Python中的图像处理库,如PIL(Pillow)。以下是大致的步骤:
- 打开分割后的图像和要叠加的图像,确保它们的尺寸相同。
- 将两个图像转换为PIL图像对象。
- 使用Pillow的图像合成功能将它们合并在一起,以实现所需的效果。
- 保存最终的结果图像。
下面是一些示例代码:
from PIL import Image
# 打开分割后的图像
segmented_image = Image.open("segmented_image.jpg")
# 打开要叠加的图像
overlay_image = Image.open("overlay_image.png")
# 确保两个图像的尺寸相同,可以使用resize()方法
overlay_image = overlay_image.resize(segmented_image.size)
# 使用Pillow的合成功能将它们合并
result_image = Image.alpha_composite(segmented_image.convert("RGBA"), overlay_image.convert("RGBA"))
# 保存最终的结果图像
result_image.save("result_image.png")
这将创建一个最终图像,其中分割后的颜色部分将叠加/更改为你的标志/logo图像,然后保存为一个新图像文件。你可以根据需要调整图像的尺寸和位置,以获得所需的效果。
英文:
This is my input image
I have this code to overlay the segmentation from input image with color
# sample execution (requires torchvision)
from PIL import Image
from torchvision import transforms
input_image = Image.open("samping.JPG")
input_image = input_image.convert("RGB")
preprocess = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
input_tensor = preprocess(input_image)
input_batch = input_tensor.unsqueeze(0) # create a mini-batch as expected by the model
# move the input and model to GPU for speed if available
if torch.cuda.is_available():
input_batch = input_batch.to('cuda')
model.to('cuda')
with torch.no_grad():
output = model(input_batch)['out'][0]
output_predictions = output.argmax(0)
# create a color pallette, selecting a color for each class
palette = torch.tensor([2 ** 25 - 1, 2 ** 15 - 1, 2 ** 21 - 1])
colors = torch.as_tensor([i for i in range(21)])[:, None] * palette
colors = (colors % 255).numpy().astype("uint8")
# plot the semantic segmentation predictions of 21 classes in each color
r = Image.fromarray(output_predictions.byte().cpu().numpy()).resize(input_image.size)
r.putpalette(colors)
And then i have this result : This is my segmented image overlay with color:
But, i want to overlay/change the color with another image, for the example this image
Result image that I want
Change the segmented plate (color) into my logo, how can i achieve that?
答案1
得分: 3
欢迎来到 SO,confuseman!
OpenCV 是一个用于计算机视觉的库,非常适用于这类任务。你可以使用 pip install opencv-python
安装它。简而言之,以下是所需步骤:
-
找出黑色像素的位置。
-
找出最大的一块黑色像素,方法是将它们转换成轮廓,然后计算它们的个体大小。(请注意,在右侧背景中突出显示的几个黑色像素)
-
找到最接近最大轮廓的旋转矩形。
-
调整叠加图像的大小并旋转它。在叠加图像周围创建一个垫子,这样在旋转时就不会被切掉。
-
将生成的叠加图像粘贴在原始图像的顶部。确保在计算位置时考虑到垫子,否则它会偏向你意图的东南方向。
import cv2
import numpy as np
# 加载图像
img = cv2.imread('stack_car.jpg')
# 用你自己的叠加图像替换它,
# 目前我会使用 Gary Larson 的“Cow Tools”,因为它展示了缩放特性,不过这张图非常棒
overlay_img = cv2.imread('cow_tools.png', -1)
# 将图像转换为灰度以便于阈值处理
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 对图像进行阈值处理
_, thresh = cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY_INV)
# 显示阈值处理后的图像
cv2.imshow('Threshold Image', thresh)
cv2.waitKey(0)
# 寻找轮廓
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 在图像副本上绘制轮廓以便可视化
img_contours = img.copy()
cv2.drawContours(img_contours, contours, -1, (0, 255, 0), 3)
cv2.imshow('Contours', img_contours)
cv2.waitKey(0)
# 找到最大一块黑色像素
max_contour = max(contours, key=cv2.contourArea)
# 获得围绕最大轮廓的旋转矩形
rotated_rect = cv2.minAreaRect(max_contour)
# 在图像副本上绘制旋转的矩形以便可视化
img_rotated_rect = img.copy()
box = cv2.boxPoints(rotated_rect)
box = np.int0(box)
cv2.drawContours(img_rotated_rect, [box], 0, (0, 0, 255), 2)
cv2.imshow('Rotated Rectangle', img_rotated_rect)
cv2.waitKey(0)
# 从旋转矩形中获取旋转角度、宽度和高度
center, (width, height), angle = rotated_rect
# 将叠加图像调整大小以匹配旋转矩形
overlay_img_resized = cv2.resize(overlay_img, (int(width), int(height)))
# 向图像添加一些透明垫子,以防旋转时被切掉
# (我对于垫子的最佳数学不确定,但是过度预估总比低估好)
pad = int(max(width, height))
overlay_img_resized = cv2.copyMakeBorder(overlay_img_resized, pad, pad, pad, pad, cv2.BORDER_CONSTANT, value=(0, 0, 0, 0))
# 按角度旋转图像
M = cv2.getRotationMatrix2D((overlay_img_resized.shape[1] / 2, overlay_img_resized.shape[0] / 2), -angle, 1)
overlay_img_resized = cv2.warpAffine(overlay_img_resized, M, (overlay_img_resized.shape[1], overlay_img_resized.shape[0]))
# 显示调整大小后的叠加图像
cv2.imshow('Resized Overlay Image', overlay_img_resized)
cv2.waitKey(0)
# 将旋转和调整大小后的图像叠加到原始图像上,
# 确保考虑到垫子,否则它会偏离你意图的东南方向
for i in range(overlay_img_resized.shape[0]):
for j in range(overlay_img_resized.shape[1]):
if overlay_img_resized[i, j][3] != 0:
img[int(center[1]-height/2)-pad+i, int(center[0]-width/2)-pad+j] = overlay_img_resized[i, j][:3]
# 显示最终图像
cv2.imshow('Final Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
英文:
Welcome to SO, confuseman!
OpenCV is a computer vision library that works really nicely for these kinds of tasks. You can install it with pip install opencv-python
. In a nutshell, here are the steps required:
- Figure out where the black pixels are located.
- Figure out where the largest chunk of black pixels exists, by converting them into contours then calculating their individual sizes. (notice the few black pixels hanging out in the back on the right side, highlighted in green)
- Find the rotated rectangle that most closely matches the largest contour.
- Resize the overlay image and rotate it. Create a pad around the overlay image so that it doesn't cut off when you rotate it.
<sup>(image used is Gary Larson's "Cow Tools", I used a tall image to showcase the scaling property)</sup>
- Paste the resulting overlay image on top of the original image. Make sure to take the pad into account when calculating the position, otherwise it will go southeast of where you intended to go.
<sup>Voila!</sup>
import cv2
import numpy as np
# Load images
img = cv2.imread('stack_car.jpg')
# Replace the overlay image with your own,
# for now I will use Gary Larson's "Cow Tools" because it showcases the
# scaling property, what a fantastic image though
overlay_img = cv2.imread('cow_tools.png', -1)
# Convert image to grayscale for easier thresholding
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Threshold the image
_, thresh = cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY_INV)
# Show the threshold image
cv2.imshow('Threshold Image', thresh)
cv2.waitKey(0)
# Find contours
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Draw contours on a copy of the image for visualization
img_contours = img.copy()
cv2.drawContours(img_contours, contours, -1, (0, 255, 0), 3)
cv2.imshow('Contours', img_contours)
cv2.waitKey(0)
# Find the largest chunk of black pixels
max_contour = max(contours, key=cv2.contourArea)
# Get a rotated box around the largest contour
rotated_rect = cv2.minAreaRect(max_contour)
# draw the rotated rectangle on a copy of the image for visualization
img_rotated_rect = img.copy()
box = cv2.boxPoints(rotated_rect)
box = np.int0(box)
cv2.drawContours(img_rotated_rect, [box], 0, (0, 0, 255), 2)
cv2.imshow('Rotated Rectangle', img_rotated_rect)
cv2.waitKey(0)
# Get the rotation angle, width, and height from the rotated rectangle
center, (width, height), angle = rotated_rect
# Resize the overlay image to match the rotated rectangle
overlay_img_resized = cv2.resize(overlay_img, (int(width), int(height)))
# Add some transparent padding to the image so that it doesn't get cut off when it rotates
# (I'm not sure of the best math for pad, but overshooting is better than undershooting)
pad = int(max(width, height))
overlay_img_resized = cv2.copyMakeBorder(overlay_img_resized, pad, pad, pad, pad, cv2.BORDER_CONSTANT, value=(0, 0, 0, 0))
# Rotate the image by the angle
M = cv2.getRotationMatrix2D((overlay_img_resized.shape[1] / 2, overlay_img_resized.shape[0] / 2), -angle, 1)
overlay_img_resized = cv2.warpAffine(overlay_img_resized, M, (overlay_img_resized.shape[1], overlay_img_resized.shape[0]))
# Show the resized overlay image
cv2.imshow('Resized Overlay Image', overlay_img_resized)
cv2.waitKey(0)
# Overlay the rotated and resized image onto the original image,
# make sure to take pad into account, otherwise it will drift southeast
for i in range(overlay_img_resized.shape[0]):
for j in range(overlay_img_resized.shape[1]):
if overlay_img_resized[i, j][3] != 0:
img[int(center[1]-height/2)-pad+i, int(center[0]-width/2)-pad+j] = overlay_img_resized[i, j][:3]
# Show the final image
cv2.imshow('Final Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论