动态规划搜索图像最佳拼接线

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

# 加载图像并转换为灰度图像
img1 = cv2.imread("1.jpg")
img2 = cv2.imread("2.jpg")

gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

# 高斯滤波
blur1 = cv2.GaussianBlur(gray1, (3, 3), 0)
blur2 = cv2.GaussianBlur(gray2, (3, 3), 0)

# 计算梯度大小矩阵
grad_x1 = cv2.Sobel(blur1, cv2.CV_32F, 1, 0, ksize=3)
grad_y1 = cv2.Sobel(blur1, cv2.CV_32F, 0, 1, ksize=3)
grad_mag1 = cv2.magnitude(grad_x1, grad_y1)
grad_x2 = cv2.Sobel(blur2, cv2.CV_32F, 1, 0, ksize=3)
grad_y2 = cv2.Sobel(blur2, cv2.CV_32F, 0, 1, ksize=3)
grad_mag2 = cv2.magnitude(grad_x2, grad_y2)

# 将梯度大小矩阵转换为能量图像
# energy1 = np.sum(grad_mag1, axis=2)
energy1 = cv2.normalize(grad_mag1, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)

# energy2 = np.sum(grad_mag2, axis=2)
energy2 = cv2.normalize(grad_mag2, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)

# 动态规划算法选择最佳路径
def find_optimal_seam(energy):
    height, width = energy.shape
    dp = np.zeros_like(energy)
    backtrack = np.zeros_like(energy, dtype=int)

    dp[0, :] = energy[0, :]

    for i in range(1, height):
        for j in range(width):
            # 处理边界情况
            if j == 0:
                indices = [j, j + 1]
            elif j == width - 1:
                indices = [j - 1, j]
            else:
                indices = [j - 1, j, j + 1]

            min_index = min(indices, key=lambda x: dp[i - 1, x])
            dp[i, j] = energy[i, j] + dp[i - 1, min_index]
            backtrack[i, j] = min_index

    # 寻找最佳路径的结束位置
    seam_end = np.argmin(dp[-1, :])

    # 回溯最佳路径
    seam = [(height - 1, seam_end)]
    for i in range(height - 2, -1, -1):
        seam_end = backtrack[i + 1, seam_end]
        seam.append((i, seam_end))
    print(seam)
    return seam  # 反转路径顺序,从上到下

seam1 = find_optimal_seam(energy1)
seam2 = find_optimal_seam(energy2)

def stitch_images(img1, img2, seam):
    height, width, _ = img1.shape
    result_height = height + len(seam)
    result_img = np.zeros((result_height, width, 3), dtype=np.uint8)

    # 复制第一张图像的像素值
    result_img[:height, :, :] = img1

    # 创建用于遮挡右侧像素的掩膜
    mask = np.ones((height, width), dtype=np.uint8)
    for i, j in seam:
        mask[i, j:] = 0

    # 根据缝合线从第二张图像中选择像素值并使用掩膜覆盖右侧像素
    seam_indices = np.array([(i, j) for i, j in seam])
    result_img[seam_indices[:, 0] + height, seam_indices[:, 1], :] = img2[seam_indices[:, 0], seam_indices[:, 1], :]
    mask[seam_indices[:, 0], seam_indices[:, 1]] = 0
    result_img[height:, :, :] *= mask[:, :, np.newaxis]

    return result_img

result_img = stitch_images(img1, img2, seam1)
def energy_to_image(energy):
    # 将能量值转换为颜色
    color_energy = cv2.applyColorMap(energy, cv2.COLORMAP_JET)
    # 转置energy的矩阵,使得能量图像较长的那个边朝向横轴
    color_energy =np.array(color_energy)
    return color_energy


def stitch_images(img1, img2, seam):
    height, width, _ = img1.shape

    # 获取拼接线的最大列数(即最右侧的列数)
    max_seam_col = max([j for _, j in seam])

    # 创建结果矩阵,宽度为两幅图像的宽度之和减去拼接线的最大列数
    result_width = width + (img2.shape[1] - max_seam_col)
    result_img = np.zeros((height, result_width, 3), dtype=np.uint8)

    # 将第一张图像复制到结果矩阵中
    result_img[:, :width, :] = img1

    # 将第二张图像复制到结果矩阵中,仅保留拼接线左侧的部分
    result_img[:, width:, :] = img2[:, max_seam_col :, :]

    return result_img


# 绘制能量图像以及拼接线
energy_img1 = energy_to_image(energy1)
energy_img2 = energy_to_image(energy2)

plt.subplot(2, 1, 1)
plt.imshow(energy_img1)
plt.plot([j for _, j in seam1], [i for i, _ in seam1], color='r', linewidth=2)

plt.subplot(2, 1, 2)
plt.imshow(energy_img2)
plt.plot([j for _, j in seam2], [i for i, _ in seam2], color='r', linewidth=2)
plt.show()
# 拼接两幅图像
result_img = stitch_images(img1, img2, seam1)

# 显示拼接结果
plt.imshow(cv2.cvtColor(result_img, cv2.COLOR_BGR2RGB))
plt.title('Stitched Image')
plt.show()

传统动态规划算法

第一步:假设能量函数图中第一行各列像素点都对应一条缝合线,其能量值大小均初始化为其对应的当前点能量值;

第二步:从第二行开始,为其每一点在上一行中选取一个最佳路径节点,选取方式的具体化方法是比较当前点正对的上一行中3个邻近点的能量值,将其中的最小值对应的列记录下来,并将该最小值与当前点对应的能量值相加来更新缝合线的能量值:

式中,表示缝合线当前的能量值,表示当前点对应的能量值。

第三步:如果缝合线当前点为图像中最后一行,则进行第四步,否则返回第二步,进行下一次扩展。

第四步:选择能量值最小的路线作为最佳缝合线:如果重叠区域中每一列都按照上述步骤计算出一条拼接线,便可以从这些拼接线中选择出最小能量值对应那条拼接线作为最佳拼接线。

传统动态规划算法在查找拼接线时,拼接节点只能在当前节点上一行中正对的三个相邻节点中选取,并且每一行只能选择一个点作为拼接点,限制了拼接线的走向,很容易导致得到拼接线从重叠区域内较大的目标上穿过。

调研发现改进的算法

可以通过数学方法计算出了重叠区域开始的第一列,重叠区域结束的最后一列,动态规划找到条最佳拼接线,并从中选择出能量最小的路线作为本文要查找的最佳拼接线,然后改进得到最佳拼接线:

第一步:初始化两个尺寸大小和E一样的二维零点矩阵M和path,并且将E的第一行的值赋给M的第一行。

第二步:从第二行开始,为列到列中的每一个点在上一行中选择一个或则多个路径节点。选取的具体方法可以是比较当前点在上一行中所有点的计算值,每一个点(i-1,k)处的值由该点在M中对应的能量值与)相加。

Si-1,j,k=t=k+1j-1Ei-1,t,k<j0t=k+1k-1Ei-1,t,k>j

Si-1,j,k表示第i-1行中的第k列到第j列之间所有点在E中的对应的能量值之和。

比较得到的第i-1行中每一点的计算值,将最小值对应的列k保存在矩阵path中(i,j)点,并将该最小值与当前点(i,j)对应的能量值E(i,j)相加起来更新当前缝合线的能量值,如下所示:

Mi,j=Ei,j+mink=1,2,3,…,col(Mi-1,k+S(i-1,j,k))

col=C2-C1,表示重叠部分的列数。

第三步:如果缝合线当前点为图像中最后一行,则进行第四步,否则返回第二步,进行下一次扩展。

第四步:选择能量值最小的路线作为最佳缝合线

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
根据提供的引用内容,最佳缝合线算法是一种图像拼接算法,可以有效地去除拼接中运动物体移动出现的鬼影。下面是一个基于Python的最佳缝合线算法的实现示例: ```python import cv2 import numpy as np # 读取待拼接图像 img1 = cv2.imread('image1.jpg') img2 = cv2.imread('image2.jpg') # 将图像转换为灰度图像 gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) # 计算SIFT特征点和描述符 sift = cv2.xfeatures2d.SIFT_create() kp1, des1 = sift.detectAndCompute(gray1, None) kp2, des2 = sift.detectAndCompute(gray2, None) # 匹配特征点 bf = cv2.BFMatcher() matches = bf.knnMatch(des1, des2, k=2) # 筛选出优秀的匹配点 good = [] for m, n in matches: if m.distance < 0.75 * n.distance: good.append(m) # 获取匹配点的坐标 src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2) dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2) # 计算最佳缝合线 M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) h, w = gray1.shape pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2) dst = cv2.perspectiveTransform(pts, M) result = cv2.polylines(img2, [np.int32(dst)], True, 255, 3, cv2.LINE_AA) # 显示拼接结果 cv2.imshow("result", result) cv2.waitKey(0) cv2.destroyAllWindows() ``` 上述代码中,我们首先读取了待拼接的两张图像,并将其转换为灰度图像。然后使用SIFT算法计算图像的特征点和描述符,并使用BFMatcher算法进行特征点匹配。接着,我们筛选出优秀的匹配点,并获取这些匹配点的坐标。最后,使用findHomography函数计算最佳缝合线,并使用perspectiveTransform函数将其应用到第二张图像上,得到拼接结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值