如何实现把有重叠的图片拼接在一起?

随便聊聊 · 1552 次浏览
用户2438453977... 创建于 2024-09-11 10:59

目的:保证分辨率足够大的前提下对地图进行截图

当前方案:先放大截图局部区域,保存到本地再用python script进行拼接;部署到gradio让没有python环境的同事可以上传图片使用,但比较繁琐

问题:quicker是否有类似的解决方案,能在没有python环境的主机中实现同样的功能?(比如我连续截图后,自动输出拼接后的图片);或者有没有可以直接对大范围的地图区域进行截图的方法(类似滑动长截图?)

 

想实现的功能:

当前的拼接方法代码:

import cv2
import numpy as np
import os 

def stitch_images(images, logger=None):
    sift = cv2.SIFT_create()
    min_match_count = 100
    stitched_img = images[0]

    for i in range(1, len(images)):
        if logger:
            logger.info(f"Processing image {i + 1} of {len(images)}")
        img1 = stitched_img
        img2 = images[i]
        keypoints1, descriptors1 = sift.detectAndCompute(img1, None)
        keypoints2, descriptors2 = sift.detectAndCompute(img2, None)
        FLANN_INDEX_KDTREE = 1
        index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
        search_params = dict(checks=50)
        flann = cv2.FlannBasedMatcher(index_params, search_params)
        matches = flann.knnMatch(descriptors1, descriptors2, k=2)

        good = []
        for m, n in matches:
            if m.distance < 0.7 * n.distance:
                good.append(m)
        
        if len(good) > min_match_count:
            if logger:
                logger.info(f"{len(good)} good matches found, min_match_count is {min_match_count}")
            src_pts = np.float32([keypoints1[m.queryIdx].pt for m in good]).reshape(-1, 2)
            dst_pts = np.float32([keypoints2[m.trainIdx].pt for m in good]).reshape(-1, 2)
            M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
            if M is None:
                if logger:
                    logger.error("Homography calculation failed.")
                return None

            h1, w1 = img1.shape[:2]
            h2, w2 = img2.shape[:2]
            pts1 = np.float32([[0,0], [0,h1], [w1,h1], [w1,0]]).reshape(-1, 1, 2)
            pts2 = np.float32([[0,0], [0,h2], [w2,h2], [w2,0]]).reshape(-1, 1, 2)
            pts2_ = cv2.perspectiveTransform(pts2, M)
            pts = np.concatenate((pts1, pts2_), axis=0)

            [x_min, y_min] = np.int32(pts.min(axis=0).ravel() - 0.5)
            [x_max, y_max] = np.int32(pts.max(axis=0).ravel() + 0.5)

            translation_dist = [-x_min, -y_min]
            H_translation = np.array([[1, 0, translation_dist[0]], [0, 1, translation_dist[1]], [0, 0, 1]])
            result_img = cv2.warpPerspective(img1, H_translation.dot(M), (x_max - x_min, y_max - y_min))
            overlap_width = min(result_img.shape[1] - translation_dist[0], w2)
            overlap_height = min(result_img.shape[0] - translation_dist[1], h2)
            
            result_img[translation_dist[1]:translation_dist[1]+overlap_height, translation_dist[0]:translation_dist[0]+overlap_width] = img2[:overlap_height, :overlap_width]
            stitched_img = result_img

        else:
            if logger:
                logger.info(f"Not enough matches are found - {len(good)}/{min_match_count}")
            return None

    stitched_img = crop_black_borders(stitched_img)

    if logger:
        logger.info("Image stitching completed")
    return stitched_img

def crop_black_borders(img):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    _, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)
    contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    if contours:
        x, y, w, h = cv2.boundingRect(contours[0])
        for contour in contours:
            x_, y_, w_, h_ = cv2.boundingRect(contour)
            x = min(x, x_)
            y = min(y, y_)
            w = max(w, w_)
            h = max(h, h_)
        cropped_img = img[y:y+h, x:x+w]
        return cropped_img
    return img

def read_image(path):
    return cv2.imdecode(np.fromfile(path, dtype=np.uint8), cv2.IMREAD_COLOR)


def save_image_with_quality(image, filename, quality=95):
    try:
        dir_path = os.path.dirname(filename)
        if not os.path.exists(dir_path):
            os.makedirs(dir_path)
            print(f"Directory {dir_path} created.")
        else:
            print(f"Directory {dir_path} already exists.")
        success = cv2.imwrite(filename, image, [int(cv2.IMWRITE_JPEG_QUALITY), quality])
        if success:
            print(f"Successfully saved image to: {filename}")
            return True
        else:
            print(f"Failed to save image to: {filename}")
            return False
    except Exception as e:
        print(f"Error saving image: {filename}. Reason: {e}")
        return False

 


回复内容
CL 2024-09-11 13:51
#1

此问题过于高深,不是很懂。 可以试下这个动作:长截图 - by toubet - 动作信息 - Quicker

回复主贴