Home > Blockchain >  Python: Accelerate numpy brute force 2d image searching
Python: Accelerate numpy brute force 2d image searching

Time:02-03

I have two images, where part of one image is present in another, however the position is not necessarily equal.

First imageSecond image

These two example images are significantly less complex than the typical drawing, so no keypoint feature matching methods will work. The objective is to find the coordinates of the top left corner of the second image that optimally joins to the two images together.

My approach is simply brute force, with a count of the black pixels to determine when the most amount of overlap has been achieved. This method works most the time, however for large images is obviously extremely slow.

Im hoping to accelerate this either with GPU acceleration or just optimisation of the method. Numba @jit decorators arent compatible with mask based numpy indexing so that wont work - the only obvious thing I can think of is cython. Cupy has also not produced good results.

Separate to reducing the number of loops (reducing search space or increasing step) are there any obvious accelerations that can be made?

 def get_overlap_box(box1, box2):
    # Unpack the coordinates of the two boxes
    x1, y1, w1, h1 = box1
    x2, y2, w2, h2 = box2

    # Calculate the horizontal overlap
    x_overlap = max(0, min(x1   w1, x2   w2) - max(x1, x2))

    # Calculate the vertical overlap
    y_overlap = max(0, min(y1   h1, y2   h2) - max(y1, y2))

    # Calculate the top-left corner of the overlap box
    x_overlap_start = max(x1, x2)
    y_overlap_start = max(y1, y2)
    return [x_overlap_start, y_overlap_start, x_overlap, y_overlap]

def find_join_point(img1, img2, step=2):
    im1h, im1w = img1.shape
    im2h, im2w = img2.shape
    canvas1 = img1.copy()
    canvas2 = img2.copy()
    count = []
    black_pixel_count_dict_reverse = {}
    for x in tqdm.tqdm(range(- im2w, im1w, step)):
        for y in range(- im2h, im1h, step):
            # get the coordinates of the two images relative to the top left corner of the first image
            box2 = [x, y, im2w, im2h]
            box1 = [0, 0, im1w , im1h]
            # Get coordinates of the overlapping box relative to the first image
            box3 = get_overlap_box(box1, box2)
            # extract the overlapping region from both canvases for comaparison
            sampleregion1 = canvas1[box3[1]:box3[3]   box3[1], box3[0]:box3[2]   box3[0]]
            replacement = sampleregion1.copy()
            sampleregion2 = canvas2[box3[1] - y:box3[3]   box3[1] - y, box3[0] - x:box3[2]   box3[0] - x]
            #Dont continue for completely white sample regions
            if np.all(sampleregion1 == 255) or np.all(sampleregion2 == 255):
                continue
            # merge the two overlapping regions
            sampleregion1[sampleregion2 == 0] = 0
            # replace the orignal with the new sample region
            canvas1[box3[1]:box3[3]   box3[1], box3[0]:box3[2]   box3[0]] = sampleregion1
            # count the black pixels across both images
            black_pixel_count = np.count_nonzero(canvas1 == 0) - np.count_nonzero(sampleregion2 == 0)
            black_pixel_count_dict_reverse[black_pixel_count] = [x, y]
            # reset the first canvas
            canvas1[box3[1]:box3[3]   box3[1], box3[0]:box3[2]   box3[0]] = replacement
            # keep the count for analysis later
            count.extend([black_pixel_count])
    # find the x,y position with the minimum black pixel count
    optimum = black_pixel_count_dict_reverse[min(count)]
    print(optimum)
    return optimum

Thanks in advance.

CodePudding user response:

If there is only translation between the two images and no rotation, what you need is to find the maximum of the cross correlation between the two images.

This is handled nicely by skimage.registration.phase_cross_correlation, and my solution below is taken from scikit-image's image registration example.

import skimage.registration

shift, _, _ = skimage.registration.phase_cross_correlation(img1, img2)

You can also use the upsample_factor keyword argument of phase_cross_correlation if you want subpixel precision of the shift between your two images.

  • Related