पायथन के साथ क्षैतिज रूप से कई छवियों को मिलाएं


121

मैं पायथन में कुछ जेपीईजी छवियों को क्षैतिज रूप से संयोजित करने का प्रयास कर रहा हूं।

संकट

मेरे पास 3 चित्र हैं - प्रत्येक 148 x 95 है - संलग्न देखें। मैंने सिर्फ एक ही छवि की 3 प्रतियां बनाईं - यही कारण है कि वे समान हैं।

यहां छवि विवरण दर्ज करेंयहां छवि विवरण दर्ज करेंयहां छवि विवरण दर्ज करें

मेरा प्रयास

मैं निम्नलिखित कोड का उपयोग करके क्षैतिज रूप से उनमें शामिल होने की कोशिश कर रहा हूं:

import sys
from PIL import Image

list_im = ['Test1.jpg','Test2.jpg','Test3.jpg']
new_im = Image.new('RGB', (444,95)) #creates a new empty image, RGB mode, and size 444 by 95

for elem in list_im:
    for i in xrange(0,444,95):
        im=Image.open(elem)
        new_im.paste(im, (i,0))
new_im.save('test.jpg')

हालाँकि, यह आउटपुट आउटपुट के रूप में संलग्न है test.jpg

यहां छवि विवरण दर्ज करें

सवाल

क्या इन छवियों को क्षैतिज रूप से समतल करने का एक तरीका है जैसे कि test.jpg में उप-छवियां अतिरिक्त छवि दिखाना नहीं है?

अतिरिक्त जानकारी

मैं एन छवियों को क्षैतिज रूप से समतल करने का एक रास्ता खोज रहा हूं। मैं आमतौर पर इस कोड का उपयोग करना चाहूंगा, इसलिए मैं निम्नलिखित करना चाहूंगा:

  • यदि संभव हो तो हार्ड-कोड छवि आयामों के लिए नहीं
  • आयामों को एक पंक्ति में निर्दिष्ट करें ताकि उन्हें आसानी से बदला जा सके

2
for i in xrange(...)आपके कोड में क्यों है ? pasteआपके द्वारा निर्दिष्ट तीन छवि फ़ाइलों का ध्यान नहीं रखना चाहिए ?
एमएसडब्ल्यू

प्रश्न, क्या आपकी छवियां हमेशा समान आकार की होंगी?
15'15


dermen: हाँ, चित्र हमेशा एक ही आकार के होंगे। msw: मुझे यकीन नहीं था कि छवियों के माध्यम से कैसे लूप किया जा सकता है, बीच में खाली जगह छोड़ने के बिना - मेरा दृष्टिकोण शायद उपयोग करने के लिए सबसे अच्छा नहीं है।
edesz

जवाबों:


171

आप ऐसा कुछ कर सकते हैं:

import sys
from PIL import Image

images = [Image.open(x) for x in ['Test1.jpg', 'Test2.jpg', 'Test3.jpg']]
widths, heights = zip(*(i.size for i in images))

total_width = sum(widths)
max_height = max(heights)

new_im = Image.new('RGB', (total_width, max_height))

x_offset = 0
for im in images:
  new_im.paste(im, (x_offset,0))
  x_offset += im.size[0]

new_im.save('test.jpg')

Test1.jpg

Test1.jpg

Test2.jpg

Test2.jpg

Test3.jpg

Test3.jpg

test.jpg

यहां छवि विवरण दर्ज करें


नेस्टेड for i in xrange(0,444,95):प्रत्येक छवि को 5 बार चिपका रहा है, 95 पिक्सेल को अलग कर दिया है। प्रत्येक बाहरी लूप पुनरावृत्ति पिछले पर चिपकाने।

for elem in list_im:
  for i in xrange(0,444,95):
    im=Image.open(elem)
    new_im.paste(im, (i,0))
  new_im.save('new_' + elem + '.jpg')

यहां छवि विवरण दर्ज करें यहां छवि विवरण दर्ज करें यहां छवि विवरण दर्ज करें


दो सवाल: 1. x_offset = 0- क्या यह छवि केंद्रों के बीच का तनाव है? 2. एक ऊर्ध्वाधर संघनन के लिए, आपका दृष्टिकोण कैसे बदलता है?
edesz

2
पेस्ट का दूसरा तर्क एक बॉक्स है। "बॉक्स का तर्क या तो 2-ट्यूपल है जो ऊपरी बाएँ कोने को देता है, 4-tuple को बाएँ, ऊपरी, दाएँ और निचले पिक्सेल समन्वय को परिभाषित करता है, या कोई नहीं (जैसा कि (0, 0))।" तो 2-टपल में हम प्रयोग कर रहे हैं x_offsetके रूप में left। ऊर्ध्वाधर कॉनैट के लिए, का ट्रैक रखें y-offset, या top। इसके बजाय sum(widths)और max(height), कर sum(heights)और max(widths)और 2-टपल बॉक्स से दूसरा तर्क का उपयोग करें। y_offsetद्वारा वेतन वृद्धि im.size[1]
शाम

21
अच्छा समाधान है। Python3 में ध्यान दें कि नक्शे केवल एक बार में पुनरावृत्त हो सकते हैं, इसलिए आपको दूसरी बार छवियों के माध्यम से पुनरावृत्ति करने से पहले फिर से चित्र = मानचित्र (Image.open, image_files) करना होगा।
नायबा

1
जैजाबा मैं आपके द्वारा बताई गई समस्या में भी भाग गया, इसलिए मैंने मैपिंग के बजाय लिस्ट कॉम्प्रिहेंशन का उपयोग करने के लिए डीटींग के समाधान को संपादित किया।
बेन क्विगले

1
मुझे mappython3.6 के बजाय लिस्ट कॉम्प्रिहेंशन का उपयोग करना था
क्लेमेंटवैल्टर

89

मैं यह कोशिश करूँगा:

import numpy as np
import PIL
from PIL import Image

list_im = ['Test1.jpg', 'Test2.jpg', 'Test3.jpg']
imgs    = [ PIL.Image.open(i) for i in list_im ]
# pick the image which is the smallest, and resize the others to match it (can be arbitrary image shape here)
min_shape = sorted( [(np.sum(i.size), i.size ) for i in imgs])[0][1]
imgs_comb = np.hstack( (np.asarray( i.resize(min_shape) ) for i in imgs ) )

# save that beautiful picture
imgs_comb = PIL.Image.fromarray( imgs_comb)
imgs_comb.save( 'Trifecta.jpg' )    

# for a vertical stacking it is simple: use vstack
imgs_comb = np.vstack( (np.asarray( i.resize(min_shape) ) for i in imgs ) )
imgs_comb = PIL.Image.fromarray( imgs_comb)
imgs_comb.save( 'Trifecta_vertical.jpg' )

यह तब तक काम करना चाहिए जब तक सभी चित्र एक ही किस्म (सभी RGB, सभी RGBA या सभी ग्रेस्केल) के हों। यह सुनिश्चित करना मुश्किल नहीं होना चाहिए कि यह कोड की कुछ और लाइनों के साथ मामला है। यहाँ मेरे उदाहरण चित्र हैं, और परिणाम:

Test1.jpg

Test1.jpg

Test2.jpg

Test2.jpg

Test3.jpg

Test3.jpg

Trifecta.jpg:

संयुक्त चित्र

Trifecta_vertical.jpg

यहां छवि विवरण दर्ज करें


बहुत बहुत धन्यवाद। एक और अच्छा जवाब। एक ऊर्ध्वाधर संघनन के लिए कैसे min_shape =....और imgs_comb....बदल जाएगा ? क्या आप यहाँ टिप्पणी के रूप में, या अपने उत्तर में पोस्ट कर सकते हैं?
edesz

3
ऊर्ध्वाधर के लिए, बदलने hstackके लिए vstack
15'15

एक और सवाल: आपकी पहली छवि ( Test1.jpg ) अन्य छवियों से बड़ी है। आपकी अंतिम (क्षैतिज या लंबवत) संक्षिप्त छवि में, सभी चित्र समान आकार के होते हैं। क्या आप बता सकते हैं कि आप पहली छवि को संक्षिप्त करने से पहले कैसे सिकुड़ सकते थे?
edesz

मैंने Image.resizeपीआईएल का इस्तेमाल किया । min_shape(मीन_प्रक्रिया, min_height) का एक टपल है और फिर (np.asarray( i.resize(min_shape) ) for i in imgs )सभी चित्रों को उस आकार में सिकोड़ देगा। वास्तव में, min_shapeक्या आपकी कोई (width,height)इच्छा हो सकती है , बस ध्यान रखें कि कम-रिज़ॉल्यूशन वाली छवियों को बड़ा करना उन्हें धुंधला बना देगा!
15'15

3
यदि आप किसी भी बारीकियों के बिना सिर्फ एक साथ छवियों को संयोजित करना चाह रहे हैं, तो यह संभवतः यहां सबसे सरल और सबसे लचीला उत्तर है। यह अलग-अलग छवि आकार, छवियों के किसी भी #, और अलग-अलग चित्र प्रारूपों के लिए खाता है। यह एक बहुत अच्छी तरह से सोचा जवाब था और उपयोगी था। सुन्न का उपयोग करने के बारे में कभी नहीं सोचा होगा। धन्यवाद।
नॉट्सोल

26

संपादित करें: DTIL का उत्तर आपके प्रश्न पर अधिक लागू है क्योंकि यह PIL का उपयोग करता है, लेकिन मैं इसे छोड़ दूंगा यदि आप यह जानना चाहते हैं कि यह कैसे करना है।

यहाँ एक सुन्न / matplotlib समाधान है जो किसी भी आकार / आकार के एन छवियों (केवल रंग छवियों) के लिए काम करना चाहिए।

import numpy as np
import matplotlib.pyplot as plt

def concat_images(imga, imgb):
    """
    Combines two color image ndarrays side-by-side.
    """
    ha,wa = imga.shape[:2]
    hb,wb = imgb.shape[:2]
    max_height = np.max([ha, hb])
    total_width = wa+wb
    new_img = np.zeros(shape=(max_height, total_width, 3))
    new_img[:ha,:wa]=imga
    new_img[:hb,wa:wa+wb]=imgb
    return new_img

def concat_n_images(image_path_list):
    """
    Combines N color images from a list of image paths.
    """
    output = None
    for i, img_path in enumerate(image_path_list):
        img = plt.imread(img_path)[:,:,:3]
        if i==0:
            output = img
        else:
            output = concat_images(output, img)
    return output

यहाँ उदाहरण का उपयोग है:

>>> images = ["ronda.jpeg", "rhod.jpeg", "ronda.jpeg", "rhod.jpeg"]
>>> output = concat_n_images(images)
>>> import matplotlib.pyplot as plt
>>> plt.imshow(output)
>>> plt.show()

यहां छवि विवरण दर्ज करें


आपका output = concat_images(output, ...मैं जब मैं यह करने के लिए एक तरह से के लिए खोज शुरू कर दिया जो खोज किया गया था। धन्यवाद।
edesz

हाय बॉल्सटैबडॉटबॉल, मेरे पास आपके उत्तर के बारे में एक प्रश्न है यदि मैं प्रत्येक उप-छवियों के लिए उप-शीर्षक जोड़ना चाहता हूं, तो यह कैसे करें? धन्यवाद।
user297850

12

DTing के जवाब के आधार पर मैंने एक ऐसा फ़ंक्शन बनाया जो उपयोग करने में आसान है:

from PIL import Image


def append_images(images, direction='horizontal',
                  bg_color=(255,255,255), aligment='center'):
    """
    Appends images in horizontal/vertical direction.

    Args:
        images: List of PIL images
        direction: direction of concatenation, 'horizontal' or 'vertical'
        bg_color: Background color (default: white)
        aligment: alignment mode if images need padding;
           'left', 'right', 'top', 'bottom', or 'center'

    Returns:
        Concatenated image as a new PIL image object.
    """
    widths, heights = zip(*(i.size for i in images))

    if direction=='horizontal':
        new_width = sum(widths)
        new_height = max(heights)
    else:
        new_width = max(widths)
        new_height = sum(heights)

    new_im = Image.new('RGB', (new_width, new_height), color=bg_color)


    offset = 0
    for im in images:
        if direction=='horizontal':
            y = 0
            if aligment == 'center':
                y = int((new_height - im.size[1])/2)
            elif aligment == 'bottom':
                y = new_height - im.size[1]
            new_im.paste(im, (offset, y))
            offset += im.size[0]
        else:
            x = 0
            if aligment == 'center':
                x = int((new_width - im.size[0])/2)
            elif aligment == 'right':
                x = new_width - im.size[0]
            new_im.paste(im, (x, offset))
            offset += im.size[1]

    return new_im

यह एक पृष्ठभूमि रंग और छवि संरेखण चुनने की अनुमति देता है। पुनरावृत्ति करना भी आसान है:

images = map(Image.open, ['hummingbird.jpg', 'tiger.jpg', 'monarch.png'])

combo_1 = append_images(images, direction='horizontal')
combo_2 = append_images(images, direction='horizontal', aligment='top',
                        bg_color=(220, 140, 60))
combo_3 = append_images([combo_1, combo_2], direction='vertical')
combo_3.save('combo_3.png')

उदाहरणस्वरूप छवि


8

यहाँ PIL में छवियों का एक ग्रिड बनाते हुए पिछले दृष्टिकोणों को सामान्य बनाने वाला एक कार्य है:

from PIL import Image
import numpy as np

def pil_grid(images, max_horiz=np.iinfo(int).max):
    n_images = len(images)
    n_horiz = min(n_images, max_horiz)
    h_sizes, v_sizes = [0] * n_horiz, [0] * (n_images // n_horiz)
    for i, im in enumerate(images):
        h, v = i % n_horiz, i // n_horiz
        h_sizes[h] = max(h_sizes[h], im.size[0])
        v_sizes[v] = max(v_sizes[v], im.size[1])
    h_sizes, v_sizes = np.cumsum([0] + h_sizes), np.cumsum([0] + v_sizes)
    im_grid = Image.new('RGB', (h_sizes[-1], v_sizes[-1]), color='white')
    for i, im in enumerate(images):
        im_grid.paste(im, (h_sizes[i % n_horiz], v_sizes[i // n_horiz]))
    return im_grid

यह ग्रिड की प्रत्येक पंक्ति और स्तंभों को न्यूनतम तक सिकोड़ देगा। आपके पास केवल एक पंक्ति हो सकती है जिसमें pil_grid (चित्र), या केवल एक स्तंभ का उपयोग करके pil_grid (चित्र, 1) हो सकता है।

सुपीरियर-सरणी आधारित समाधानों पर पीआईएल का उपयोग करने का एक लाभ यह है कि आप संरचित छवियों को अलग तरह से समझ सकते हैं (जैसे ग्रेस्केल या पैलेट-आधारित चित्र)।

उदाहरण आउटपुट

def dummy(w, h):
    "Produces a dummy PIL image of given dimensions"
    from PIL import ImageDraw
    im = Image.new('RGB', (w, h), color=tuple((np.random.rand(3) * 255).astype(np.uint8)))
    draw = ImageDraw.Draw(im)
    points = [(i, j) for i in (0, im.size[0]) for j in (0, im.size[1])]
    for i in range(len(points) - 1):
        for j in range(i+1, len(points)):
            draw.line(points[i] + points[j], fill='black', width=2)
    return im

dummy_images = [dummy(20 + np.random.randint(30), 20 + np.random.randint(30)) for _ in range(10)]

pil_grid(dummy_images):

line.png

pil_grid(dummy_images, 3):

यहां छवि विवरण दर्ज करें

pil_grid(dummy_images, 1):

यहां छवि विवरण दर्ज करें


Pil_grid में यह पंक्ति: h_sizes, v_sizes = [0] * n_horiz, [0] * (n_images // n_horiz) पढ़ना चाहिए: h_sizes, v_sizes = [0] * n_horiz, [0] * ((n_images // n_horiz) + (1 if n_images % n_horiz > 0 else 0)) कारण: यदि क्षैतिज चौड़ाई पूर्णांक में छवियों की संख्या को विभाजित नहीं करती है, तो आपको अधूरी रेखा के लिए अतिरिक्त की आवश्यकता होगी।
बर्नहार्ड वैगनर

3

यदि सभी छवि की ऊँचाई समान हैं,

imgs = [‘a.jpg’, b.jpg’, c.jpg’]
concatenated = Image.fromarray(
  np.concatenate(
    [np.array(Image.open(x)) for x in imgs],
    axis=1
  )
)

हो सकता है कि आप इस तरह सम्‍मिलित होने से पहले छवियों का आकार बदल सकें,

imgs = [‘a.jpg’, b.jpg’, c.jpg’]
concatenated = Image.fromarray(
  np.concatenate(
    [np.array(Image.open(x).resize((640,480)) for x in imgs],
    axis=1
  )
)

1
सरल और आसान। धन्यवाद
माइक डी क्लार्क

2

यहाँ मेरा समाधान है:

from PIL import Image


def join_images(*rows, bg_color=(0, 0, 0, 0), alignment=(0.5, 0.5)):
    rows = [
        [image.convert('RGBA') for image in row]
        for row
        in rows
    ]

    heights = [
        max(image.height for image in row)
        for row
        in rows
    ]

    widths = [
        max(image.width for image in column)
        for column
        in zip(*rows)
    ]

    tmp = Image.new(
        'RGBA',
        size=(sum(widths), sum(heights)),
        color=bg_color
    )

    for i, row in enumerate(rows):
        for j, image in enumerate(row):
            y = sum(heights[:i]) + int((heights[i] - image.height) * alignment[1])
            x = sum(widths[:j]) + int((widths[j] - image.width) * alignment[0])
            tmp.paste(image, (x, y))

    return tmp


def join_images_horizontally(*row, bg_color=(0, 0, 0), alignment=(0.5, 0.5)):
    return join_images(
        row,
        bg_color=bg_color,
        alignment=alignment
    )


def join_images_vertically(*column, bg_color=(0, 0, 0), alignment=(0.5, 0.5)):
    return join_images(
        *[[image] for image in column],
        bg_color=bg_color,
        alignment=alignment
    )

इन चित्रों के लिए:

images = [
    [Image.open('banana.png'), Image.open('apple.png')],
    [Image.open('lime.png'), Image.open('lemon.png')],
]

परिणाम इस तरह दिखेंगे:


join_images(
    *images,
    bg_color='green',
    alignment=(0.5, 0.5)
).show()

यहां छवि विवरण दर्ज करें


join_images(
    *images,
    bg_color='green',
    alignment=(0, 0)

).show()

यहां छवि विवरण दर्ज करें


join_images(
    *images,
    bg_color='green',
    alignment=(1, 1)
).show()

यहां छवि विवरण दर्ज करें


1
""" 
merge_image takes three parameters first two parameters specify 
the two images to be merged and third parameter i.e. vertically
is a boolean type which if True merges images vertically
and finally saves and returns the file_name
"""
def merge_image(img1, img2, vertically):
    images = list(map(Image.open, [img1, img2]))
    widths, heights = zip(*(i.size for i in images))
    if vertically:
        max_width = max(widths)
        total_height = sum(heights)
        new_im = Image.new('RGB', (max_width, total_height))

        y_offset = 0
        for im in images:
            new_im.paste(im, (0, y_offset))
            y_offset += im.size[1]
    else:
        total_width = sum(widths)
        max_height = max(heights)
        new_im = Image.new('RGB', (total_width, max_height))

        x_offset = 0
        for im in images:
            new_im.paste(im, (x_offset, 0))
            x_offset += im.size[0]

    new_im.save('test.jpg')
    return 'test.jpg'

1
from __future__ import print_function
import os
from pil import Image

files = [
      '1.png',
      '2.png',
      '3.png',
      '4.png']

result = Image.new("RGB", (800, 800))

for index, file in enumerate(files):
path = os.path.expanduser(file)
img = Image.open(path)
img.thumbnail((400, 400), Image.ANTIALIAS)
x = index // 2 * 400
y = index % 2 * 400
w, h = img.size
result.paste(img, (x, y, x + w, y + h))

result.save(os.path.expanduser('output.jpg'))

उत्पादन

यहां छवि विवरण दर्ज करें


0

बस पहले से सुझाए गए समाधानों को जोड़ना। समान ऊंचाई मान लेता है, कोई आकार नहीं देता।

import sys
import glob
from PIL import Image
Image.MAX_IMAGE_PIXELS = 100000000  # For PIL Image error when handling very large images

imgs    = [ Image.open(i) for i in list_im ]

widths, heights = zip(*(i.size for i in imgs))
total_width = sum(widths)
max_height = max(heights)

new_im = Image.new('RGB', (total_width, max_height))

# Place first image
new_im.paste(imgs[0],(0,0))

# Iteratively append images in list horizontally
hoffset=0
for i in range(1,len(imgs),1):
    **hoffset=imgs[i-1].size[0]+hoffset  # update offset**
    new_im.paste(imgs[i],**(hoffset,0)**)

new_im.save('output_horizontal_montage.jpg')

0

मेरा समाधान होगा:

import sys
import os
from PIL import Image, ImageFilter
from PIL import ImageFont
from PIL import ImageDraw 

os.chdir('C:/Users/Sidik/Desktop/setup')
print(os.getcwd())

image_list= ['IMG_7292.jpg','IMG_7293.jpg','IMG_7294.jpg', 'IMG_7295.jpg' ]

image = [Image.open(x) for x in image_list]  # list
im_1 = image[0].rotate(270)
im_2 = image[1].rotate(270)
im_3 = image[2].rotate(270)
#im_4 = image[3].rotate(270)

height = image[0].size[0]
width = image[0].size[1]
# Create an empty white image frame
new_im = Image.new('RGB',(height*2,width*2),(255,255,255))

new_im.paste(im_1,(0,0))
new_im.paste(im_2,(height,0))
new_im.paste(im_3,(0,width))
new_im.paste(im_4,(height,width))


draw = ImageDraw.Draw(new_im)
font = ImageFont.truetype('arial',200)

draw.text((0, 0), '(a)', fill='white', font=font)
draw.text((height, 0), '(b)', fill='white', font=font)
draw.text((0, width), '(c)', fill='white', font=font)
#draw.text((height, width), '(d)', fill='white', font=font)

new_im.show()
new_im.save('BS1319.pdf')   
[![Laser spots on the edge][1]][1]
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.