从图像拼接中删除黑色虚线

Posted

技术标签:

【中文标题】从图像拼接中删除黑色虚线【英文标题】:remove black dashed lines from image stitching 【发布时间】:2021-10-04 11:56:56 【问题描述】:

我正在拼接多个图像。在拼接两个图像时,它在拼接之间显示黑色虚线,如下所示。

有谁知道我如何删除或摆脱这条黑色虚线?

拼接代码的主要部分,它拼接两个图像并使用前一个拼接图像的结果调用下一个图像,直到所有图像都结束:

detector = cv2.xfeatures2d.SURF_create(400)
gray1 = cv2.cvtColor(image1,cv2.COLOR_BGR2GRAY)
ret1, mask1 = cv2.threshold(gray1,1,255,cv2.THRESH_BINARY)
kp1, descriptors1 = detector.detectAndCompute(gray1,mask1)

gray2 = cv2.cvtColor(image2,cv2.COLOR_BGR2GRAY)
ret2, mask2 = cv2.threshold(gray2,1,255,cv2.THRESH_BINARY)
kp2, descriptors2 = detector.detectAndCompute(gray2,mask2)

keypoints1Im = cv2.drawKeypoints(image1, kp1, outImage = cv2.DRAW_MATCHES_FLAGS_DEFAULT, color=(0,0,255))
util.display("KEYPOINTS",keypoints1Im)
keypoints2Im = cv2.drawKeypoints(image2, kp2, outImage = cv2.DRAW_MATCHES_FLAGS_DEFAULT, color=(0,0,255))
util.display("KEYPOINTS",keypoints2Im)

matcher = cv2.BFMatcher()
matches = matcher.knnMatch(descriptors2,descriptors1, k=2)

good = []
for m, n in matches:
    if m.distance < 0.55 * n.distance:
        good.append(m)

print (str(len(good)) + " Matches were Found")

if len(good) <= 10:
    return image1

matches = copy.copy(good)

matchDrawing = util.drawMatches(gray2,kp2,gray1,kp1,matches)
util.display("matches",matchDrawing)

src_pts = np.float32([ kp2[m.queryIdx].pt for m in matches ]).reshape(-1,1,2)
dst_pts = np.float32([ kp1[m.trainIdx].pt for m in matches ]).reshape(-1,1,2)

A = cv2.estimateRigidTransform(src_pts,dst_pts,fullAffine=False)

if A is None:
    HomogResult = cv2.findHomography(src_pts,dst_pts,method=cv2.RANSAC)
    H = HomogResult[0]

height1,width1 = image1.shape[:2]
height2,width2 = image2.shape[:2]

corners1 = np.float32(([0,0],[0,height1],[width1,height1],[width1,0]))
corners2 = np.float32(([0,0],[0,height2],[width2,height2],[width2,0]))

warpedCorners2 = np.zeros((4,2))

for i in range(0,4):
    cornerX = corners2[i,0]
    cornerY = corners2[i,1]
    if A is not None: #check if we're working with affine transform or perspective transform
        warpedCorners2[i,0] = A[0,0]*cornerX + A[0,1]*cornerY + A[0,2]
        warpedCorners2[i,1] = A[1,0]*cornerX + A[1,1]*cornerY + A[1,2]
    else:
        warpedCorners2[i,0] = (H[0,0]*cornerX + H[0,1]*cornerY + H[0,2])/(H[2,0]*cornerX + H[2,1]*cornerY + H[2,2])
        warpedCorners2[i,1] = (H[1,0]*cornerX + H[1,1]*cornerY + H[1,2])/(H[2,0]*cornerX + H[2,1]*cornerY + H[2,2])

allCorners = np.concatenate((corners1, warpedCorners2), axis=0)

[xMin, yMin] = np.int32(allCorners.min(axis=0).ravel() - 0.5)
[xMax, yMax] = np.int32(allCorners.max(axis=0).ravel() + 0.5)

translation = np.float32(([1,0,-1*xMin],[0,1,-1*yMin],[0,0,1]))
warpedResImg = cv2.warpPerspective(image1, translation, (xMax-xMin, yMax-yMin))


if A is None:
    fullTransformation = np.dot(translation,H) #again, images must be translated to be 100% visible in new canvas
    warpedImage2 = cv2.warpPerspective(image2, fullTransformation, (xMax-xMin, yMax-yMin))

else:
    warpedImageTemp = cv2.warpPerspective(image2, translation, (xMax-xMin, yMax-yMin))
    warpedImage2 = cv2.warpAffine(warpedImageTemp, A, (xMax-xMin, yMax-yMin))

result = np.where(warpedImage2 != 0, warpedImage2, warpedResImg)

请帮帮我。谢谢。

编辑:

输入图片1(调整大小)

输入图像2(调整大小)

结果(调整大小)

更新:

@fmw42 anwser 之后的结果:

【问题讨论】:

作为猜测,我怀疑它在你的最后一行result = np.where(warpedImage2 != 0, warpedImage2, warpedResImg) 中是“warpedImage2 != 0”。您正在从边缘的二元决策中获得楼梯混叠。两侧的边缘很可能会使用插值中的黑色进行抗锯齿处理,因此它们有一些黑色与实际颜色混合。你可以尝试一些测试。使用最近邻插值进行 warpAffine,看看在这些接缝处会发生什么。您也可以尝试使用“warpedImage2 @fmw42 感谢您的回复。我不是专业人士,因此无法正确理解您的评论。但我试过warpedImage2 = cv2.warpAffine(warpedImageTemp, A, (xMax-xMin, yMax-yMin),cv2.INTER_NEAREST)ret1, mask1 = cv2.threshold(gray1,120,255,cv2.THRESH_BINARY) 仍然没有删除黑线。如果可能,请让我知道我需要更改和测试什么。 要尝试的一件事是 cv2.warpAffine() 中的不同标志(插值)。见docs.opencv.org/4.1.1/da/d54/… 和docs.opencv.org/4.1.1/da/d54/… 要尝试的另一件事是将 result = np.where(warpedImage2 != 0, warpedImage2, warpedResImg) 中的 warpedImage2 != 0 更改为 warpedImage2 &lt;T,在其中将 T 设置为不同的值。从 32 岁开始。看看会发生什么。然后加倍或减半,看看会发生什么。 @ fmw42 with T=64 及以上结果图像如问题所示。其他更改没有得到正确的结果。 【参考方案1】:

出现问题是因为当您进行变形时,图像的边界像素会被重新采样/插值成黑色背景像素。这会在您的扭曲图像周围留下一个非零边框,该边框具有不同的值,当与其他图像合并时,这些边框会显示为您的暗虚线。发生这种情况是因为您的合并测试是二进制的,使用 != 0 进行测试。

因此,您可以做的一件简单的事情是在 Python/OpenCV 中对扭曲的图像进行遮罩,以从图像外部的黑色背景中获取其边界,然后侵蚀遮罩。然后使用遮罩侵蚀图像边界。这可以通过对您的最后几行代码进行以下更改来实现,如下所示:

if A is None:
    fullTransformation = np.dot(translation,H) #again, images must be translated to be 100% visible in new canvas
    warpedImage2 = cv2.warpPerspective(image2, fullTransformation, (xMax-xMin, yMax-yMin))

else:
    warpedImageTemp = cv2.warpPerspective(image2, translation, (xMax-xMin, yMax-yMin))
    warpedImage2 = cv2.warpAffine(warpedImageTemp, A, (xMax-xMin, yMax-yMin))
    mask2 = cv2.threshold(warpedImage2, 0, 255, cv2.THRESH_BINARY)[1]
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
    mask2 = cv2.morphologyEx(mask2, cv2.MORPH_ERODE, kernel)
    warpedImage2[mask2==0] = 0

result = np.where(warpedImage2 != 0, warpedImage2, warpedResImg)

我只是在您的代码中添加了以下代码行:

mask2 = cv2.threshold(warpedImage2, 0, 255, cv2.THRESH_BINARY)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
mask2 = cv2.morphologyEx(mask2, cv2.MORPH_ERODE, kernel)
warpedImage2[mask2==0] = 0

如果需要更多腐蚀,您可以增加内核大小。

这是之前和之后。请注意,我没有 SURF 并尝试使用 ORB,但没有很好地对齐。所以你的道路不对齐。但是由于未对齐导致的不匹配强调了这个问题,因为它显示了虚线锯齿状的黑色边界线。 ORB 不起作用或我没有从上面得到适当的代码来使其对齐的事实并不重要。遮罩可以满足您的需求,并且可以扩展到处理您的所有图像。

与上述结合可以完成的另一件事是羽化蒙版,然后使用蒙版渐变混合两个图像。这是通过模糊蒙版(再多一点)然后将值拉伸到模糊边界的内半部分并使渐变仅在模糊边界的外半部分来完成的。然后将两个图像与渐变蒙版及其反转混合,如下所示,代码与上面相同。

    if A is None:
        fullTransformation = np.dot(translation,H) #again, images must be translated to be 100% visible in new canvas
        warpedImage2 = cv2.warpPerspective(image2, fullTransformation, (xMax-xMin, yMax-yMin))
    
    else:
        warpedImageTemp = cv2.warpPerspective(image2, translation, (xMax-xMin, yMax-yMin))
        warpedImage2 = cv2.warpAffine(warpedImageTemp, A, (xMax-xMin, yMax-yMin))
        mask2 = cv2.threshold(warpedImage2, 0, 255, cv2.THRESH_BINARY)[1]
        kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
        mask2 = cv2.morphologyEx(mask2, cv2.MORPH_ERODE, kernel)
        warpedImage2[mask2==0] = 0
        mask2 = cv2.blur(mask2, (5,5))
        mask2 = skimage.exposure.rescale_intensity(mask2, in_range=(127.5,255), out_range=(0,255)).astype(np.float64)
    
    result = (warpedImage2 * mask2 +  warpedResImg * (255 - mask2))/255
    result = result.clip(0,255).astype(np.uint8)

cv2.imwrite("image1_image2_merged3.png", result)

对比原始合成结果如下:

添加

我已更正我的 ORB 代码以反转图像的使用,现在它对齐了。所以这里列出了所有 3 种技术:原始技术、仅使用二进制蒙版的技术和使用渐变蒙版进行混合的技术(均如上所述)。

添加2

这里是 3 个请求的图像:原始、二进制蒙版、渐变蒙版混合。

这是我上面最后一个版本的 ORB 代码

我试图尽可能少地改变你的代码,除了我必须使用 ORB 并且我不得不在接近尾声时交换名称 image1 和 image2。

import cv2
import matplotlib.pyplot as plt
import numpy as np
import itertools
from scipy.interpolate import UnivariateSpline
from skimage.exposure import rescale_intensity


image1 = cv2.imread("image1.jpg")
image2 = cv2.imread("image2.jpg")

gray1 = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)

# Detect ORB features and compute descriptors.
MAX_FEATURES = 500
GOOD_MATCH_PERCENT = 0.15
orb = cv2.ORB_create(MAX_FEATURES)

keypoints1, descriptors1 = orb.detectAndCompute(gray1, None)
keypoints2, descriptors2 = orb.detectAndCompute(gray2, None)

# Match features.
matcher = cv2.DescriptorMatcher_create(cv2.DESCRIPTOR_MATCHER_BRUTEFORCE_HAMMING)
matches = matcher.match(descriptors1, descriptors2, None)

# Sort matches by score
matches.sort(key=lambda x: x.distance, reverse=False)

# Remove not so good matches
numGoodMatches = int(len(matches) * GOOD_MATCH_PERCENT)
matches = matches[:numGoodMatches]

# Draw top matches
imMatches = cv2.drawMatches(image1, keypoints1, image2, keypoints2, matches, None)
cv2.imwrite("/Users/fred/desktop/image1_image2_matches.png", imMatches)

# Extract location of good matches
points1 = np.zeros((len(matches), 2), dtype=np.float32)
points2 = np.zeros((len(matches), 2), dtype=np.float32)

for i, match in enumerate(matches):
    points1[i, :] = keypoints1[match.queryIdx].pt
    points2[i, :] = keypoints2[match.trainIdx].pt

print(points1)
print("")
print(points2)

A = cv2.estimateRigidTransform(points1,points2,fullAffine=False)
#print(A)

if A is None:
    HomogResult = cv2.findHomography(points1,points2,method=cv2.RANSAC)
    H = HomogResult[0]

height1,width1 = image1.shape[:2]
height2,width2 = image2.shape[:2]

corners1 = np.float32(([0,0],[0,height1],[width1,height1],[width1,0]))
corners2 = np.float32(([0,0],[0,height2],[width2,height2],[width2,0]))

warpedCorners2 = np.zeros((4,2))

# project corners2 into domain of image1 from A affine or H homography
for i in range(0,4):
    cornerX = corners2[i,0]
    cornerY = corners2[i,1]
    if A is not None: #check if we're working with affine transform or perspective transform
        warpedCorners2[i,0] = A[0,0]*cornerX + A[0,1]*cornerY + A[0,2]
        warpedCorners2[i,1] = A[1,0]*cornerX + A[1,1]*cornerY + A[1,2]
    else:
        warpedCorners2[i,0] = (H[0,0]*cornerX + H[0,1]*cornerY + H[0,2])/(H[2,0]*cornerX + H[2,1]*cornerY + H[2,2])
        warpedCorners2[i,1] = (H[1,0]*cornerX + H[1,1]*cornerY + H[1,2])/(H[2,0]*cornerX + H[2,1]*cornerY + H[2,2])

allCorners = np.concatenate((corners1, warpedCorners2), axis=0)

[xMin, yMin] = np.int32(allCorners.min(axis=0).ravel() - 0.5)
[xMax, yMax] = np.int32(allCorners.max(axis=0).ravel() + 0.5)

translation = np.float32(([1,0,-1*xMin],[0,1,-1*yMin],[0,0,1]))
warpedResImg = cv2.warpPerspective(image2, translation, (xMax-xMin, yMax-yMin))


if A is None:
    fullTransformation = np.dot(translation,H) #again, images must be translated to be 100% visible in new canvas
    warpedImage2 = cv2.warpPerspective(image2, fullTransformation, (xMax-xMin, yMax-yMin))

else:
    warpedImageTemp = cv2.warpPerspective(image1, translation, (xMax-xMin, yMax-yMin))
    warpedImage2 = cv2.warpAffine(warpedImageTemp, A, (xMax-xMin, yMax-yMin))
    mask2 = cv2.threshold(warpedImage2, 0, 255, cv2.THRESH_BINARY)[1]
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
    mask2 = cv2.morphologyEx(mask2, cv2.MORPH_ERODE, kernel)
    warpedImage2[mask2==0] = 0
    mask2 = cv2.blur(mask2, (5,5))
    mask2 = rescale_intensity(mask2, in_range=(127.5,255), out_range=(0,255)).astype(np.float64)

result = (warpedImage2 * mask2 +  warpedResImg * (255 - mask2))/255
result = result.clip(0,255).astype(np.uint8)

cv2.imwrite("image1_image2_merged2.png", result)

您有以下情况。请注意与我上面的代码相比,名称 image1 和 image2 的使用位置。

warpedResImg = cv2.warpPerspective(image1, translation, (xMax-xMin, yMax-yMin))


if A is None:
    fullTransformation = np.dot(translation,H) #again, images must be translated to be 100% visible in new canvas
    warpedImage2 = cv2.warpPerspective(image2, fullTransformation, (xMax-xMin, yMax-yMin))

else:
    warpedImageTemp = cv2.warpPerspective(image2, translation, (xMax-xMin, yMax-yMin))
    warpedImage2 = cv2.warpAffine(warpedImageTemp, A, (xMax-xMin, yMax-yMin))

【讨论】:

你能不能发一张非 gif 版本的最终结果图片,这样大家可以比较而不会头疼? 感谢您的回答。我试过你的代码。现在没有黑线,但我的问题中更新了轻微的错位和缝合边缘效果。是因为你用的是ORB而我用的是SURF吗?我尝试了 ORB,但它给了我不到 10 个匹配点,所以没有拼接图像。我该如何改进呢?我使用了你的代码部分,但没有得到像你这样的结果。 使用 ORB 可能会有所不同。如果设置正确,SURF 或 SIFT 应该没问题。我的附加代码独立于这些技术。它只是混合而不做任何几何调整,除了在混合之前稍微去除图像外部周围的一排暗像素之外。由于我没有安装 SURF,我现在无法测试您的代码。您发布的代码有些奇怪,因为我必须在最后交换 image1 和 image2 以使它们对齐,正如我提到的那样。那是为什么?你的代码真的适用于上面的例子吗? @fmw42 我使用了您的代码并在我的代码中更改了该部分(如果其他部分)。因此,黑线已被删除,但您的 ADDITION2 中提到的渐变蒙版混合没有出现在我的结果中,如问题更新中所示。如果您可以请提供您的整个代码,那么我可以检查有什么区别。我正在为多个图像执行代码。正确设置 SURF/SIFT 是什么意思?另外,如果您可以提供我可以学习这些技术的参考资料,这些参考资料会有所帮助。谢谢 您在哪里交换了图像?如果你可以在你的代码中评论那是什么,那将很容易理解。抱歉,因为我是新手并且正在学习东西,所以我收到了很多问题,这些术语和技术不容易理解。【参考方案2】:

水平胶合

我将专注于其中一个剪辑作为概念证明。我同意 cmets 的观点,即您的代码有点冗长且难以使用。所以第一步是自己粘贴图片。

import cv2
import matplotlib.pyplot as plt
import numpy as np
import itertools
from scipy.interpolate import UnivariateSpline

upper_image = cv2.cvtColor(cv2.imread('yQv6W.jpg'), cv2.COLOR_BGR2RGB)/255
lower_image = cv2.cvtColor(cv2.imread('zoWJv.jpg'), cv2.COLOR_BGR2RGB)/255

result_image = np.zeros((466+139,700+22,3))
result_image[139:139+lower_image.shape[0],:lower_image.shape[1]] = lower_image
result_image[0:upper_image.shape[0], 22:22+upper_image.shape[1]] = upper_image
plt.imshow(result_image)

好的,没有黑色虚线,但我承认也不完美。所以下一步是至少对齐图片最右边的街道和小路。为此,我需要将图片缩小为非整数大小并将其转回网格。我将使用类似knn 的方法。

编辑:根据 cmets 中的要求,我将更详细地解释收缩,因为它必须再次手动完成以进行其他缝合。魔法发生在一行中(我将 n 替换为它的值)

f = UnivariateSpline([0,290,510,685],[0,310,530,700])

我首先尝试在 x 方向上缩放下图,以使最右边的小路适合上图。不幸的是,这条街不适合这条街。所以我所做的就是根据上面的功能进行缩小。在像素 0 我仍然想要像素零,在 290 我想要拥有以前在 310 的像素,依此类推。 请注意,290,510 和 310,530 分别是胶合高度处街道和道路的新旧 x 坐标。

class Image_knn():
    def fit(self, image):
        self.image = image.astype('float')

    def predict(self, x, y):
        image = self.image
        weights_x = [(1-(x % 1)).reshape(*x.shape,1), (x % 1).reshape(*x.shape,1)]
        weights_y = [(1-(y % 1)).reshape(*x.shape,1), (y % 1).reshape(*x.shape,1)]
        start_x = np.floor(x).astype('int')
        start_y = np.floor(y).astype('int')
        return sum([image[np.clip(np.floor(start_x + x), 0, image.shape[0]-1).astype('int'),
                          np.clip(np.floor(start_y + y), 0, image.shape[1]-1).astype('int')] * weights_x[x]*weights_y[y] 
                    for x,y in itertools.product(range(2),range(2))])

image_model = Image_knn()
image_model.fit(lower_image)

n = 685
f = UnivariateSpline([0,290,510,n],[0,310,530,700])
np.linspace(0,lower_image.shape[1],n)
yspace = f(np.arange(n))

result_image = np.zeros((466+139,700+22, 3))
a,b = np.meshgrid(np.arange(0,lower_image.shape[0]), yspace)
result_image[139:139+lower_image.shape[0],:n] = np.transpose(image_model.predict(a,b), [1,0,2])
result_image[0:upper_image.shape[0], 22:22+upper_image.shape[1]] = upper_image
plt.imshow(result_image, 'gray')

好多了,没有黑线,但也许我们仍然可以稍微平滑切割。我想如果我在剪裁处采用上下图像的凸组合,它看起来会更好。

result_image = np.zeros((466+139,700+22,3))
a,b = np.meshgrid(np.arange(0,lower_image.shape[0]), yspace)
result_image[139:139+lower_image.shape[0],:n] = np.transpose(image_model.predict(a,b), [1,0,2])

transition_range = 10
result_image[0:upper_image.shape[0]-transition_range, 22:22+upper_image.shape[1]] = upper_image[:-transition_range,:]
transition_pixcels = upper_image[-transition_range:,:]*np.linspace(1,0,transition_range).reshape(-1,1,1)
result_image[upper_image.shape[0]-transition_range:upper_image.shape[0], 22:22+upper_image.shape[1]] *= np.linspace(0,1,transition_range).reshape(-1,1,1)
result_image[upper_image.shape[0]-transition_range:upper_image.shape[0], 22:22+upper_image.shape[1]] += transition_pixcels
plt.imshow(result_image)
plt.savefig('text.jpg')

倾斜胶合

为了完整起见,这里还有一个顶部粘上倾斜底部的版本。我将图片附在某个点上,然后将fixed point 转了几度。最后,我再次纠正了一些非常轻微的不一致。为了获得我正在使用 jupyter lab 和 %matplotlib widget 的坐标。

fixed_point_upper = np.array([139,379])
fixed_point_lower = np.array([0,400])
angle = np.deg2rad(2)
down_dir = np.array([np.sin(angle+np.pi/2),np.cos(angle+np.pi/2)])
right_dir = np.array([np.sin(angle),np.cos(angle)])

result_image_height = np.ceil((fixed_point_upper+lower_image.shape[0]*down_dir+(lower_image.shape[1]-fixed_point_lower[1])*right_dir)[0]).astype('int')
right_shift = np.ceil(-(fixed_point_upper+lower_image.shape[0]*down_dir-fixed_point_lower[1]*right_dir)[1]).astype('int')
result_image_width = right_shift+upper_image.shape[1]
result_image = np.zeros([result_image_height, result_image_width,3])
fixed_point_result = np.array([fixed_point_upper[0],fixed_point_upper[1]+right_shift])

lower_top_left = fixed_point_result-fixed_point_lower[1]*right_dir
result_image[:upper_image.shape[0],-upper_image.shape[1]:] = upper_image

# calculate points in lower_image
result_coordinates = np.stack(np.where(np.ones(result_image.shape[:2],dtype='bool')),axis=1)
lower_coordinates = np.stack([(result_coordinates-lower_top_left)@down_dir,(result_coordinates-lower_top_left)@right_dir],axis=1)
mask = (0 <= lower_coordinates[:,0]) & (0 <= lower_coordinates[:,1]) \
    & (lower_coordinates[:,0] <= lower_image.shape[0]) & (lower_coordinates[:,1] <= lower_image.shape[1])
result_coordinates = result_coordinates[mask]
lower_coordinates = lower_coordinates[mask]

# COORDINATES ON RESULT IMAGE
# left street 254
# left sides of houses 295, 420, 505
# right small street, both sides big street 590,635,664

# COORDINATES ON LOWER IMAGE
# left street 234
# left sides of houses 280, 399, 486
# right small street, both sides big street 571, 617, 642

def coord_transform(y): 
    return (y-lower_top_left[1])/right_dir[1]
y = tuple(map(coord_transform, [lower_top_left[1], 254, 295, 420, 505, 589, 635, 664]))
f = UnivariateSpline(y,[0, 234, 280, 399, 486, 571, 617, 642])
result_image[result_coordinates[:,0],result_coordinates[:,1]] = image_model.predict(lower_coordinates[:,0],np.vectorize(f)(lower_coordinates[:,1]))

【讨论】:

平滑剪切是有效的,但当您将剪切设置为水平时更容易。当您在扭曲一个或两个图像后有一个不规则的切割曲线是一个角度而不是一条直线时,您可以这样做吗?这就是困难。当您尝试在图像的极端处合并时,如果它们不重叠甚至重叠。这不是一个简单的过程。 感谢您的回答。结果拼接很好,但我们可以得到图像的原始颜色吗?此代码是否适用于多个图像拼接? 这里我给出了两张图片的结果。事实上,我正在拼接多个具有高分辨率的图像。您在代码中使用的整数值可以在拼接时说,与其他输入拼接时也一样吗? @fmw42 我认为应该是可能的。如果您提出新问题,请提供我愿意尝试的两张图片中的图片和匹配曲线。 @ganesh 我认为颜色应该没问题。您需要采用我的Image_knn 来处理 3d 图像,或者每种颜色使用 3 次。

以上是关于从图像拼接中删除黑色虚线的主要内容,如果未能解决你的问题,请参考以下文章

在 OpenCV 图像拼接中混合伪影

opencv掩模图像是啥意思

OpenCV 将浮点数据输入图像拼接过程

如何从文本图像中删除虚线带?

目标检测图像裁剪/标签可视化/图像拼接处理脚本

目标检测图像裁剪/标签可视化/图像拼接处理脚本