Combine blocks of different images and produce a new image

后端 未结 2 1093
小蘑菇
小蘑菇 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))
    

提交回复
热议问题