Сохранение массива numpy в изображение сжимает части изображения до неправильного размера - PullRequest
2 голосов
/ 10 февраля 2020

Я столкнулся с этой проблемой, когда выяснял, как экспортировать внешние изображения в скрипт blender. Но я думаю, что это больше не относится к блендеру, а к numpy и способам обработки массивов. Вот пост о первой проблеме.

Таким образом, проблема заключается в том, что при сохранении массива numpy в изображение он будет искажен и будет несколько одинаковых изображений. Посмотрите на изображение ниже для лучшего понимания.

Цель состоит в том, чтобы выяснить, как заставить это работать с numpy и python, используя собственные пиксельные данные блендера. Поэтому избегайте использования таких библиотек, как PIL или cv2, которые не включены в блендер python.

enter image description here

При сохранении данных, где есть изображения, все является окончательным размер работает правильно. И при попытке объединить 4 меньших фрагмента в окончательное увеличенное изображение оно не было правильно экспортировано.

Я сделал пример скрипта с python в блендере, чтобы продемонстрировать проблему:

# Example script to show how to merge external images in Blender
# using numpy. In this example we use 4 images (2x2) that should
# be merged to one actual final image. 
# Regular (not cropped render borders) seems to work fine but
# how to merge cropped images properly???
#
# Usage: Just run script and it will export image named "MERGED_IMAGE"
# to root of this project folder and you'll see what's the problem.

import bpy, os
import numpy as np

ctx = bpy.context
scn = ctx.scene

print('START')

# Get all image files
def get_files_in_folder(path):
    path = bpy.path.abspath(path)
    render_files = []
    for root, dirs, files in os.walk(path):
        for file in files:
            if (file.lower().endswith(('.png', '.jpg', '.jpeg', '.tiff', '.bmp', '.gif'))):
                render_files.append(file)
    return render_files

def merge_images(image_files, image_cropped = True):

    image_pixels = []
    final_image_pixels = 0

    print(image_files)

    for file in image_files:
        if image_cropped is True:
            filepath = bpy.path.abspath('//Cropped\\' + file)
        else:
            filepath = bpy.path.abspath('//Regular\\' + file)
        loaded_pixels = bpy.data.images.load(filepath, check_existing=True).pixels
        image_pixels.append(loaded_pixels)

    np_array = np.array(image_pixels)

    # Merge images
    if image_cropped:
        final_image_pixels = np_array
        # HOW MERGE PROPERLY WHEN USING CROPPED IMAGES???
    else:
        for arr in np_array:
            final_image_pixels += arr

    # Save output image
    output_image = bpy.data.images.new('MERGED_IMAGE', alpha=True, width=256, height=256)
    output_image.file_format = 'PNG'
    output_image.alpha_mode = 'STRAIGHT'
    output_image.pixels = final_image_pixels.ravel()
    output_image.filepath_raw = bpy.path.abspath("//MERGED_IMAGE.png")
    output_image.save()   

images_cropped = get_files_in_folder("//Cropped")
images_regular = get_files_in_folder('//Regular')

# Change between these to get different example
merge_images(images_cropped)
#merge_images(images_regular, False)

print('END')

Итак Я предполагаю, что проблема связана с тем, как обрабатывать пиксельные данные изображения и массивы с помощью numpy.

. Здесь находится папка проекта в zip-файле, содержащая пример рабочего сценария тестирования, где вы можете проверить, как это работает в blender. https://drive.google.com/file/d/1R4G_fubEzFWbHZMLtAAES-QsRhKyLKWb/view?usp=sharing

1 Ответ

1 голос
/ 11 февраля 2020

Поскольку все ваши изображения имеют одинаковое измерение 128x128, а изображения OpenCV представляют собой Numpy массивы, здесь есть три метода. Вы можете сохранить изображение, используя cv2.imwrite.

Входные изображения:

enter image description here enter image description here enter image description here enter image description here

Метод № 1: np.hstack + np.vstack

hstack1 = np.hstack((image1, image2))
hstack2 = np.hstack((image3, image4))
hstack_result = np.vstack((hstack1, hstack2))

Метод № 2: np.concatenate

concatenate1 = np.concatenate((image1, image2), axis=1)
concatenate2 = np.concatenate((image3, image4), axis=1)
concatenate_result = np.concatenate((concatenate1, concatenate2), axis=0) 

Метод № 3: cv2.hconcat + cv2.vconcat

hconcat1 = cv2.hconcat([image1, image2])
hconcat2 = cv2.hconcat([image3, image4])
hconcat_result = cv2.vconcat([hconcat1, hconcat2])

Результат должен быть одинаковым для всех методов

enter image description here

Полный код

import cv2
import numpy as np

# Load images
image1 = cv2.imread('Fart_1_2.png')
image2 = cv2.imread('Fart_2_2.png')
image3 = cv2.imread('Fart_1_1.png')
image4 = cv2.imread('Fart_2_1.png')

# Method #1
hstack1 = np.hstack((image1, image2))
hstack2 = np.hstack((image3, image4))
hstack_result = np.vstack((hstack1, hstack2))

# Method #2
concatenate1 = np.concatenate((image1, image2), axis=1)
concatenate2 = np.concatenate((image3, image4), axis=1)
concatenate_result = np.concatenate((concatenate1, concatenate2), axis=0) 

# Method #3
hconcat1 = cv2.hconcat([image1, image2])
hconcat2 = cv2.hconcat([image3, image4])
hconcat_result = cv2.vconcat([hconcat1, hconcat2])

# Display
cv2.imshow('concatenate_result', concatenate_result)
cv2.imshow('hstack_result', hstack_result)
cv2.imshow('hconcat_result', hconcat_result)
cv2.waitKey()
...