使用OpenCV合并两张图片

97

我正在尝试使用OpenCV 2.1将两张图片合并成一张,并将它们相邻放置。在Python中,我正在执行以下操作:

import numpy as np, cv

img1 = cv.LoadImage(fn1, 0)
img2 = cv.LoadImage(fn2, 0)

h1, w1 = img1.height,img1.width
h2, w2 = img2.height,img2.width

# Create an array big enough to hold both images next to each other.
vis = np.zeros((max(h1, h2), w1+w2), np.float32)

mat1 = cv.CreateMat(img1.height,img1.width, cv.CV_32FC1)
cv.Convert( img1, mat1 )

mat2 = cv.CreateMat(img2.height, img2.width, cv.CV_32FC1)
cv.Convert( img2, mat2 )

# Copy both images into the composite image.
vis[:h1, :w1] = mat1
vis[:h2, w1:w1+w2] = mat2

h,w = vis.shape
vis2 = cv.CreateMat(h, w, cv.CV_32FC3)
vis0 = cv.fromarray(vis)
cv.CvtColor(vis0, vis2, cv.CV_GRAY2BGR)
cv.ShowImage('test', vis2)
cv.WaitKey()

两个输入图像分别为:

https://code.ros.org/trac/opencv/browser/trunk/opencv/samples/c/box.png?rev=2270

https://code.ros.org/trac/opencv/browser/trunk/opencv/samples/c/box_in_scene.png?rev=2270

生成的图像为:

enter image description here

尽管大部分图像是白色的,与网站的其他部分难以区分,但这些白色区域对应的是各个图像应该出现的位置。黑色区域则表示没有写入任何图像数据。

为什么我的所有图像数据都转换成了白色?


你看过OpenCV 2.3.1中的find_obj.py示例吗?它看起来正是你想要做的。 - Andrey Kamaev
@Andrey,是的,这实际上就是我正在尝试转换为OpenCV 2.1的内容。 我没有2.3版本也无法编译它,所以现在我正在使用2.1版本。 - Cerin
您还可以针对编译问题提出问题。我认为它是可以解决的。请注意,由于flann索引的python绑定仅在OpenCV 2.3.1中添加,因此无法使用OpenCV 2.1实现此示例中的flann部分。 - Andrey Kamaev
2
你也可以使用 cv2.vconcat()cv2.hconcat(),参见这里:https://dev59.com/fWUq5IYBdhLWcg3wV_Ai#72177160 - Jeru Luke
7个回答

174

如果您的图像大小相同(这是显示图像处理结果的常见情况),您可以使用numpy的concatenate来简化您的代码。

要垂直堆叠(img1在img2上方):

vis = np.concatenate((img1, img2), axis=0)

要水平堆叠(img1 在 img2 左侧):

vis = np.concatenate((img1, img2), axis=1)

验证:

import cv2
import numpy as np
img1 = cv2.imread('img1.png')
img2 = cv2.imread('img2.png')
vis = np.concatenate((img1, img2), axis=1)
cv2.imwrite('out.png', vis)

out.png图像将在左侧包含img1,右侧包含img2。


5
这并非总是如此。“ValueError: all the input array dimensions except for the concatenation axis must match exactly” - FindOutIslamNow
1
你如何为两个图像重叠添加偏移量? - Lorenzo Sciuto

45

对于那些想要将两张彩色图像合并成一张的人,这是对 Andrey 的回答稍作修改,适用于我的方法:

对于希望将两个颜色图像合并为一个的人,这是对Andrey答案的轻微修改,适用于我:

img1 = cv2.imread(imageFile1)
img2 = cv2.imread(imageFile2)

h1, w1 = img1.shape[:2]
h2, w2 = img2.shape[:2]

#create empty matrix
vis = np.zeros((max(h1, h2), w1+w2,3), np.uint8)

#combine 2 images
vis[:h1, :w1,:3] = img1
vis[:h2, w1:w1+w2,:3] = img2

这段代码对我有效。我不确定为什么推荐使用“np.concatenate”的方式在我的情况下效果不佳(显示不同的图片)。我怀疑是因为它只连接一个轴而不是两个。提示:如果是灰度图像,请删除3。 - Semooze

23

您还可以使用OpenCV的内置函数cv2.hconcatcv2.vconcat,它们分别用于水平和垂直拼接图像,与其名称所示。

import cv2

img1 = cv2.imread('opencv/lena.jpg')
img2 = cv2.imread('opencv/baboon.jpg')

v_img = cv2.vconcat([img1, img2])
h_img = cv2.hconcat([img1, img2])

cv2.imshow('Horizontal', h_img)
cv2.imshow('Vertical', v_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

水平拼接

Horizontal

垂直拼接

Vertical


2
快速问题,如何在水平方向上进行串联,其中一个图像需要占据3/4的空间? - Akhil Nadh PC

22
import numpy as np, cv2

img1 = cv2.imread(fn1, 0)
img2 = cv2.imread(fn2, 0)
h1, w1 = img1.shape[:2]
h2, w2 = img2.shape[:2]
vis = np.zeros((max(h1, h2), w1+w2), np.uint8)
vis[:h1, :w1] = img1
vis[:h2, w1:w1+w2] = img2
vis = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR)

cv2.imshow("test", vis)
cv2.waitKey()

或者如果你喜欢传统的方式:

import numpy as np, cv

img1 = cv.LoadImage(fn1, 0)
img2 = cv.LoadImage(fn2, 0)

h1, w1 = img1.height,img1.width
h2, w2 = img2.height,img2.width
vis = np.zeros((max(h1, h2), w1+w2), np.uint8)
vis[:h1, :w1] = cv.GetMat(img1)
vis[:h2, w1:w1+w2] = cv.GetMat(img2)
vis2 = cv.CreateMat(vis.shape[0], vis.shape[1], cv.CV_8UC3)
cv.CvtColor(cv.fromarray(vis), vis2, cv.CV_GRAY2BGR)

cv.ShowImage("test", vis2)
cv.WaitKey()

2
cv2.COLOR_GRAY2BGR 在 OpenCV 2.3 中似乎不存在。此外,您读取灰度图像并将其转换回 RGB。因此,您的结果将是灰度的,对吗? - dmorlock
2
我们可以对彩色图像做到这一点吗? - Krish

6
为了水平堆叠:
imgHor = np.hstack((img, img))

为了垂直堆叠:
imgVer = np.vstack((img, img))

为了显示:
cv2.imshow("Horizontal", imgHor) # horizontal stack
cv2.imshow("Vertical", imgVer)   # vertical stack

1

使用一行代码的三种最佳方法

import cv2
import numpy as np 


img = cv2.imread('Imgs/Saint_Roch_new/data/Point_4_Face.jpg')
dim = (256, 256)
resizedLena = cv2.resize(img, dim, interpolation = cv2.INTER_LINEAR)
X, Y = resizedLena, resizedLena

# Methode 1: Using Numpy (hstack, vstack)
Fusion_Horizontal = np.hstack((resizedLena, Y, X))
Fusion_Vertical   = np.vstack((newIMG, X))

cv2.imshow('Fusion_Vertical using vstack', Fusion_Vertical)
cv2.waitKey(0)

# Methode 2: Using Numpy (contanate)
Fusion_Vertical   = np.concatenate((resizedLena, X, Y), axis=0)
Fusion_Horizontal = np.concatenate((resizedLena, X, Y), axis=1)

cv2.imshow("Fusion_Horizontal usung concatenate", Fusion_Horizontal)
cv2.waitKey(0)


# Methode 3: Using OpenCV (vconcat, hconcat)
Fusion_Vertical   = cv2.vconcat([resizedLena, X, Y])
Fusion_Horizontal = cv2.hconcat([resizedLena, X, Y])

cv2.imshow("Fusion_Horizontal Using hconcat", Fusion_Horizontal)
cv2.waitKey(0)

-2

在OpenCV 3.0中,你可以很容易地使用它,如下所示:

#combine 2 images same as to concatenate images with two different sizes
h1, w1 = img1.shape[:2]
h2, w2 = img2.shape[:2]
#create empty martrix (Mat)
res = np.zeros(shape=(max(h1, h2), w1 + w2, 3), dtype=np.uint8)
# assign BGR values to concatenate images
for i in range(res.shape[2]):
    # assign img1 colors
    res[:h1, :w1, i] = np.ones([img1.shape[0], img1.shape[1]]) * img1[:, :, i]
    # assign img2 colors
    res[:h2, w1:w1 + w2, i] = np.ones([img2.shape[0], img2.shape[1]]) * img2[:, :, i]

output_img = res.astype('uint8')

这段代码构造了一个结果数组,假设它的高度为两个图像中较高的那个。 -- 完全不需要循环或np.ones()乘法。 - Christoph Rackwitz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接