目的:保证分辨率足够大的前提下对地图进行截图
当前方案:先放大截图局部区域,保存到本地再用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