Combine blocks of different images and produce a new image

后端 未结 2 1069
小蘑菇
小蘑菇 2021-01-23 15:55

I have six photographs. I changed them into block structure. Consider an image of size 200x200. 1. I converted into blocks of 10x10 so now I have 400 blocks in total each of siz

相关标签:
2条回答
  • 2021-01-23 16:19

    So, here's my approach to your problem. I rewrote parts of your code to get rid of all the lists, and solely working on NumPy arrays. Therefore, I store all images in a 4D array, and store all calculated "block means" in a 3D array. Finally, I use the found image_number array to generate some kind of "index array" by using OpenCV's resize method with INTER_AREA interpolation flag ("resampling using pixel area relation"). In doing so, the generation of your final image can be done very easily using NumPy's boolean array indexing.

    Let's have a look at the following code:

    import cv2
    import numpy as np
    
    # Read images in one single 4D array; resize to [200, 200]
    nImages = 3
    images = np.zeros((200, 200, 3, nImages), np.uint8)
    images[:, :, :, 0] = cv2.resize(cv2.imread('U2Gmz.png', cv2.IMREAD_COLOR), (200, 200))
    images[:, :, :, 1] = cv2.resize(cv2.imread('OZxf3.png', cv2.IMREAD_COLOR), (200, 200))
    images[:, :, :, 2] = cv2.resize(cv2.imread('aISEB.png', cv2.IMREAD_COLOR), (200, 200))
    
    # Calculate block means and store in one single 3D array
    means = np.zeros((20, 20, nImages), np.uint8)
    for im in range(nImages):
        arr = np.split(images[:, :, :, im], 20)
        arr = np.array([np.split(x, 20, 1) for x in arr])
        means[:, :, im] = np.reshape([arr[i][j].mean() for i in range(20) for j in range(20)], (20, 20))
    
    # Determine block mean maximum over all images
    result = np.max(means, axis=2)
    
    # Determine index of block mean maximum over all images
    image_number = np.argmax(means, axis=2)
    print(image_number)
    
    # Resize index array with "resampling using pixel area relation" to final image size
    image_number_idx = cv2.resize(np.uint8(image_number), (200, 200), interpolation=cv2.INTER_AREA)
    
    # Generate final image by boolean array indexing
    final = np.zeros((200, 200, 3), np.uint8)
    for im in range(nImages):
        idx = image_number_idx == im
        final[idx, :] = images[idx, :, im]
    
    # Show images
    cv2.imshow('image1', images[:, :, :, 0])
    cv2.imshow('image2', images[:, :, :, 1])
    cv2.imshow('image3', images[:, :, :, 2])
    cv2.imshow('final', final)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    These are the used images:

    The image_number output gives this:

    [[0 0 0 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0]
     [1 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0]
     [1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0]
     [0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1]
     [0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 1 1 0]
     [0 0 0 0 0 0 0 2 1 1 1 2 0 0 0 0 0 1 0 0]
     [0 0 0 0 0 0 0 2 1 0 0 2 2 2 0 0 0 1 1 0]
     [0 0 0 0 0 2 2 2 1 0 2 2 2 2 0 0 0 1 1 0]
     [0 0 0 0 0 2 2 2 0 0 0 0 2 2 2 0 0 0 0 0]
     [0 0 0 0 2 2 2 2 0 0 0 0 2 2 2 2 0 0 0 0]
     [0 0 0 0 2 0 2 2 0 0 0 0 2 0 0 0 0 0 0 0]
     [1 1 0 0 0 2 2 0 0 2 2 0 0 2 0 0 0 0 0 0]
     [1 1 0 0 2 2 2 0 2 2 2 2 1 2 2 2 2 0 2 1]
     [1 0 0 0 0 2 2 2 2 0 2 2 2 2 2 2 0 1 1 1]
     [1 1 1 0 0 2 2 2 1 1 1 2 2 2 2 0 0 1 1 0]
     [1 1 1 1 1 1 1 1 1 1 1 2 0 0 1 0 0 0 0 0]
     [1 1 1 1 1 1 0 1 1 1 1 1 0 2 0 0 0 0 0 0]
     [1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
     [1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0]
     [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1]]
    

    And, the final image looks like this:

    I hope, I understood your question correctly, and this is what you wanted to achieve.

    My assumption is, that all input images have the same image dimensions, (200, 200) here. Otherwise, I couldn't think of a way to manage potentially varying block sizes, if just the "grid", (20, 20) here, is fixed.

    Hope that helps!

    EDIT: To read all jpg files from the given folder, you might use:

    files = glob.glob('resized/*.jpg')
    
    # Read images in one single 4D array; resize to [200, 200]
    nImages = len(files)
    images = np.zeros((200, 200, 3, nImages), np.uint8)
    for im in range(nImages):
        images[:, :, :, im] = cv2.resize(cv2.imread(files[im], cv2.IMREAD_COLOR), (200, 200))
    
    0 讨论(0)
  • 2021-01-23 16:40

    I consider you wonder to know how to merge two or more images. In python, when you load an image using opencv, it is stored in numpy arrays. So it is easy using numpy. Below is an example to merge two images. Firstly, load two images:

    import cv2
    import numpy as np
    
    img1 = cv2.imread('pic1.png')
    img2 = cv2.imread('pic2.png')
    
    cv2.imshow('img1', img1)
    cv2.imshow('img2', img2)
    

    the two images are like:

    Then to merge those two imgs:

    # get the height and width of those pictures
    h1, w1 = img1.shape[:2]
    h2, w2 = img2.shape[:2]
    
    # define the height and width of the merged pictures
    h, w = max(h1, h2), w1 + w2
    img = np.zeros((h, w, 3), np.uint8)
    
    # paste each img to the right place
    img[0:h1, 0:w1] = img1
    img[0:h2, w1:] = img2
    
    cv2.imshow('img', img)
    cv2.waitKey(0)
    

    the result would be like:

    0 讨论(0)
提交回复
热议问题