Home > Net >  Stitching computer images by feature without warping (no camera images)
Stitching computer images by feature without warping (no camera images)

Time:08-16

I've did quite a search about image stitching on python and most are for panoramic images, warping and rotating the images to combine them into one.

What I'm trying to do is using computer images, so they are digital and can be template matched without a problem, it will always be 2D without need of warping.

Basically here I have pieces of a map that is zoomed in and I want to make a massive image of this small pictures, here we have all the images used: 1-4 stitched

But once I stitch the fifth image it seems to have wrong match and incorrectly, but I always get the best match by distance on NORM_HAMMING, this is the result: enter image description here

The thing is, this is the first image, in this order, that the best match point (var start) is negative in the x axis, here is the matching points in the imgur order:

  1. (7, 422)
  2. (786, 54)
  3. (394, 462)
  4. (-350, 383)

I attempted switching the top image, doing specific code for negative match but I've believe I was deviating the performance.

Also noting from the docs the first image should be the query and the second supposed to be the target, but I couldn't get it to work by inverting the vis variable in function param.

CodePudding user response:

The main issue here was when recognized points weren't on the screen (negative values), it needs offsets to adjust, I also incremented a little bit to the code and verified if the matches were legit, as if all the calculated displacement were in average the around the matched first pick in brute force.

with the average of 2MB for each image, without preprocessing the images/downscaling/compressing, after stitching 9 images together I got the average of 1050ms in my PC, as for other algorithms tested (that warped the image) took around 2-3seconds for stitching 2 of those images.

here is the final result:

import os
import numpy as np
import cv2

def averageTuple(tupleList):
    avgX, avgY = 0,0
    for tuple in tupleList:
        avgX  = tuple[0]
        avgY  = tuple[1]
    return (int(avgX/len(tupleList)),int(avgY/len(tupleList)))

def tupleInRange(t1, t2, dif=3):
    if t1[0]   dif > t2[0] and t1[0] - dif < t2[0]:
        if t1[1]   dif > t2[1] and t1[1] - dif < t2[1]:
            return True
    return False

def rgbToRGBA(img):
    b_channel, g_channel, r_channel = cv2.split(img)
    alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255
    return cv2.merge((b_channel, g_channel, r_channel, alpha_channel))

def cropAlpha(img,extraRange=0.05):
    y, x = img[:, :, 3].nonzero()  # get the nonzero alpha coordinates
    minx = int(np.min(x)*(1-extraRange))
    miny = int(np.min(y)*(1-extraRange))
    maxx = int(np.max(x)*(1 extraRange))
    maxy = int(np.max(y)*(1 extraRange))
    return img[miny:maxy, minx:maxx]

def stitchImagesWithoutWarp(img1, img2):
    if len(cv2.split(img1)) != 4:
        img1 = rgbToRGBA(img1)
    if len(cv2.split(img2)) != 4:
        img2 = rgbToRGBA(img2)

    orb = cv2.ORB_create()
    kp1, des1 = orb.detectAndCompute(img1,None)
    kp2, des2 = orb.detectAndCompute(img2,None)
    bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
    matches = bf.match(des1,des2)
    matches = sorted(matches, key = lambda x:x.distance)
    good_matches = matches[:10]
    src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1,1,2)
    dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1,1,2)

    pointsList = []
    for index in range(0,len(src_pts)):
        curPoint = (int(dst_pts[index][0][0]-src_pts[index][0][0])), (int(dst_pts[index][0][1]-src_pts[index][0][1]))
        pointsList.append(curPoint)

    start = pointsList[0]
    avgTuple = averageTuple(pointsList)
    if not tupleInRange(start, avgTuple): return img1

    h1, w1 = img1.shape[:2]
    h2, w2 = img2.shape[:2]
    ax = abs(start[0])
    ay = abs(start[1])
    vis = np.zeros((ay h1,ax w1,4), np.uint8)

    ofst2 = (ax if start[0]<0 else 0, ay if start[1]<0 else 0)
    ofst1 = (0 if start[0]<0 else ax, 0 if start[1]<0 else ay)
    vis[ofst1[1]:ofst1[1] h1, ofst1[0]:ofst1[0] w1, :4] = img1
    vis[ofst2[1]:ofst2[1] h2, ofst2[0]:ofst2[0] w2, :4] = img2
    return cropAlpha(vis)

imgList = []
for it in os.scandir("images"):
    imgList.append(cv2.imread(it.path))

vis = stitchImagesWithoutWarp(imgList[0],imgList[1])
for index in range(2,len(imgList)):
    vis = stitchImagesWithoutWarp(vis,imgList[index])
cv2.imwrite("output.png", cropAlpha(vis,0))

here is the output image (compressed in JPEG for stackoverflow): enter image description here

  • Related