**泊松编辑技术**

泊松编辑是一种图像合成技术,它允许用户将一个区域(源区域)从一个图像(源图像)无缝地复制到另一个图像(目标图像)中,同时保持源区域在目标图像中的外观和光影效果一致。这种技术通过求解泊松方程来实现,可以确保复制的区域与目标图像的背景自然融合,常用于图像修复、对象插入等场景。

**图像拼接技术**

图像拼接是将多幅图像组合成一幅单一的、连贯的图像的过程。它通常涉及到图像的对齐、变换和融合等步骤,以确保拼接后的图像在视觉上是一致的。图像拼接技术广泛应用于全景摄影、图像增强、视频监控等领域,可以为用户提供更广阔的视野或更丰富的图像信息。

**颜色转移技术**

颜色转移是一种图像处理技术,它将一幅图像(源图像)的色彩特征转移到另一幅图像(目标图像)上。这种技术通过分析源图像和目标图像的颜色分布,然后应用某种算法(如颜色映射、颜色直方图匹配等)来改变目标图像的颜色,使其反映源图像的调色板和色调。颜色转移技术常用于图像美化、风格转换等场景。


好,以下是速成品,所以很简单,还有点拙劣。

看(参考)吧。

实践成果

Poisson Editing

方案文件目录:

要融合的源图像:

要融合到的目标图像:

生成的掩码:

融合结果:

完整代码:

import cv2
import numpy as np

def create_mask(image_path, mask_path, top_left, bottom_right):
    """
    为给定图像创建一个掩码,掩码中包含一个矩形区域
    :param image_path: 要创建掩码的图像路径。
    :param mask_path: 保存掩码图像的路径。
    :param top_left: 矩形的左上角坐标 (x, y)。
    :param bottom_right: 矩形的右下角坐标 (x, y)。
    """
    # 加载图像
    image = cv2.imread(image_path)
    # 创建一个与图像相同尺寸的黑色掩码
    mask = np.zeros(image.shape[:2], dtype="uint8")
    # 在掩码上绘制白色矩形
    cv2.rectangle(mask, top_left, bottom_right, 255, -1)
    # 羽化掩码边缘
    mask = cv2.GaussianBlur(mask, (5, 5), 0)
    # 保存掩码
    cv2.imwrite(mask_path, mask)


def poisson_blend(source_img, target_img, mask_img, center):
    """
    执行泊松编辑,将源图像融合到目标图像中。

    :param source_img: 要融合的源图像。
    :param target_img: 要融合到的目标图像。
    :param mask_img: 指示融合区域的掩码图像。
    :param center: 在目标图像上放置源图像的中心点坐标。
    :return: 融合后的图像。
    """
    # 确保掩码是单通道8位图像
    if mask_img.dtype != np.uint8:
        mask_img = mask_img.astype(np.uint8)

    # 确保掩码图像中至少有一个非零像素
    if np.count_nonzero(mask_img) == 0:
        raise ValueError("掩码图像中没有非零像素。")

    # 确保源图像、目标图像和掩码图像的尺寸兼容
    if source_img.shape[:2] != mask_img.shape:
        source_img = cv2.resize(source_img, (mask_img.shape[1], mask_img.shape[0]))

    # 确保中心点坐标在目标图像的范围内
    if center[0] < 0 or center[0] >= target_img.shape[1] or center[1] < 0 or center[1] >= target_img.shape[0]:
        raise ValueError("中心点坐标超出目标图像范围。")

    # 执行泊松编辑
    blended_img = cv2.seamlessClone(source_img, target_img, mask_img, center, cv2.MIXED_CLONE) # 还有NORMAL_CLONE、MONOCHROME_TRANSFER

    return blended_img

# 图像路径
source_path = 'area_source/source.jpg'
target_path = 'target_image/target.jpg'
mask_path = 'mask_image/mask.png'

# 定义掩码的矩形区域
top_left = (20, 20)
bottom_right = (346, 257)

# 创建掩码
create_mask(source_path, mask_path, top_left, bottom_right)

# 加载图像
source_img = cv2.imread(source_path)
target_img = cv2.imread(target_path)
mask_img = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE)

# 确保源图像和掩码尺寸相同
source_img = cv2.resize(source_img, (mask_img.shape[1], mask_img.shape[0]))
# 定义在目标图像上放置源图像的中心点
center = (target_img.shape[1] // 2, target_img.shape[0] // 2)
# 执行泊松编辑
blended_img = poisson_blend(source_img, target_img, mask_img, center)

# 保存或显示结果
cv2.imwrite('result_image/blended_result.jpg', blended_img)
cv2.imshow('融合后的图像', blended_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Image Stitching

方案文件的目录:

进行拼接图片:

  

拼接结果:

完整代码:

import cv2 as cv
import numpy as np
import os

MIN = 10

def direct_stiching(warpImg, img1):
    direct = warpImg.copy()
    direct[0:img1.shape[0], 0:img1.shape[1]] = img1
    return direct


def optimize_stiching(warpImg, img1):
    # 重叠部分进行过渡处理。
    rows, cols = img1.shape[:2]

    left = 0  # 开始重叠的最左端
    right = cols  # 开始重叠的最右端,默认就是img1的最右端

    for col in range(0, cols):  # 找到重叠的最左端
        if img1[:, col].any() and warpImg[:, col].any():
            left = col
            break

    res = np.zeros([rows, cols, 3], np.uint8)

    for row in range(0, rows):
        for col in range(0, right):
            # 如果左图没有像素点,就赋值为右图像素点
            if not img1[row, col].any():
                res[row, col] = warpImg[row, col]
            # 如果右图没有像素点就赋值为左图像素点
            elif not warpImg[row, col].any():
                res[row, col] = img1[row, col]
            # 如果都有像素点,就进行二者的权融合,alpha代表距离谁更近,谁的权重更大
            else:
                srcImgLen = float(abs(col - left))
                testImgLen = float(abs(col - right))
                alpha = srcImgLen / (srcImgLen + testImgLen)
                res[row, col] = np.clip(img1[row, col] * (1 - alpha) + warpImg[row, col] * (alpha), 0, 255)

    warpImg[0:img1.shape[0], 0:img1.shape[1]] = res

    return warpImg


if __name__ == '__main__':

    pic1 = "part_of_image/dong1.jpg"
    pic2 = "part_of_image/dong2.jpg"

    img1 = cv.imread(pic1)
    img2 = cv.imread(pic2)
    # cv.imshow("Image1", img1)
    # cv.imshow("Image2", img2)

    print('img1 Dimensions : ', img1.shape)
    print('img2 Dimensions : ', img2.shape)

    # sift提取特征
    sift = cv.SIFT_create(nfeatures=0, nOctaveLayers=3, contrastThreshold=0.04, edgeThreshold=10, sigma=1.6)
    kp1, describe1 = sift.detectAndCompute(img1, None)
    kp2, describe2 = sift.detectAndCompute(img2, None)

    # FLANN 进行特征点匹配
    FLANN_INDEX_KDTREE = 1
    indexParams = dict(algorithm=FLANN_INDEX_KDTREE, trees=4)
    searchParams = dict(checks=32)
    flann = cv.FlannBasedMatcher(indexParams, searchParams)
    match = flann.knnMatch(describe1, describe2, k=2)

    good = []
    for i, (m, n) in enumerate(match):
        if m.distance < 0.6 * n.distance:
            good.append(m)

    result = cv.drawMatches(img1, kp1, img2, kp2, good, None)
    #cv.imshow("matches", result)

    # 指定保存目录
    save_dir = "stitched_image"
    if not os.path.exists(save_dir):
        os.makedirs(save_dir)

    # 保存matches结果图
    matches_filename = os.path.join(save_dir, "matches.jpg")
    cv.imwrite(matches_filename, result)

    # RANSAC:findhomography
    if len(good) > MIN:
        src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)
        ano_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)
        M, mask = cv.findHomography(ano_pts, src_pts, cv.RANSAC, 5.0)
        warpImg = cv.warpPerspective(img2, M, (
        img1.shape[1] + img2.shape[1], max(img2.shape[0], img1.shape[0])))  # 把img2变到img1的坐标系下,放在一张大图上。

        direct = direct_stiching(warpImg, img1)  # 直接将左图覆盖warpImg的左区域
        optimize = optimize_stiching(warpImg, img1)  # 左图和右图的重叠区域进行加权融合

        base_filename = os.path.join(save_dir, os.path.splitext(os.path.basename(pic1))[0])
        cv.imwrite(base_filename + '_direct.jpg', direct)
        cv.imwrite(base_filename + '_optimize.jpg', optimize)
        print("result saved to directory:", save_dir)
        cv.waitKey()
        cv.destroyAllWindows()

    else:
        print("not enough matches!")

Color Transfer

方案文件的目录:

运行结果示例:

完整代码:

import cv2 as cv
import numpy as np

def match_histograms(source, template):
    """
    将源图像的颜色直方图匹配到模板图像的颜色直方图。
    """
    # 将图像转换到LAB颜色空间
    source = cv.cvtColor(source, cv.COLOR_BGR2LAB)
    template = cv.cvtColor(template, cv.COLOR_BGR2LAB)

    # 计算源图像和模板图像的直方图
    (l, a, b) = cv.split(source)
    (tl, ta, tb) = cv.split(template)
    source_hist = [cv.calcHist([channel], [0], None, [256], [0, 256]) for channel in [l, a, b]]
    template_hist = [cv.calcHist([channel], [0], None, [256], [0, 256]) for channel in [tl, ta, tb]]

    # 计算累积分布函数
    source_cdf = [np.cumsum(hist) / hist.sum() for hist in source_hist]
    template_cdf = [np.cumsum(hist) / hist.sum() for hist in template_hist]

    # 创建映射表
    mapped_values = [np.interp(source_cdf[i], template_cdf[i], np.arange(256)) for i in range(3)]

    # 应用映射表
    (l, a, b) = [cv.LUT(channel, mapped_values[i].astype("uint8")) for i, channel in enumerate([l, a, b])]

    # 合并通道
    matched = cv.merge([l, a, b])
    matched = cv.cvtColor(matched, cv.COLOR_LAB2BGR)
    return matched

def color_transfer(source_path, target_path, output_path):
    # 读取源图像和目标图像
    source = cv.imread(source_path)
    target = cv.imread(target_path)

    # 检查图像是否正确读取
    if source is None or target is None:
        print("Error: Could not read one or both images.")
        return

    # 进行颜色直方图匹配
    matched_target = match_histograms(target, source)

    # 保存结果
    cv.imwrite(output_path, matched_target)

if __name__ == "__main__":
    source_path = 'color_tones/source_image.jpg'  # 源图像路径
    target_path = 'target_image/target_image.jpg'  # 目标图像路径
    output_path = 'transfer_result/color_transferred_image.jpg'  # 输出图像路径

    # 确保输出目录存在
    import os
    os.makedirs(os.path.dirname(output_path), exist_ok=True)

    color_transfer(source_path, target_path, output_path)
    print(f"Color transferred image saved to {output_path}")

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐