মেমরিতে চিত্র লোড না করে চিত্রের আকার পান


113

আমি বুঝতে পারি যে আপনি নিম্নলিখিত ফ্যাশনে পিআইএল ব্যবহার করে চিত্রের আকার পেতে পারেন

from PIL import Image
im = Image.open(image_filename)
width, height = im.size

যাইহোক, আমি ইমেজ প্রস্থ ও উচ্চতা পেতে চাই ছাড়া মেমরি চিত্রটি লোড হতে হচ্ছে। এটা কি সম্ভব? আমি কেবল চিত্রের আকারের পরিসংখ্যানই করছি এবং চিত্রের সামগ্রীর জন্য যত্ন নেব না। আমি কেবল আমার প্রসেসিংটি আরও দ্রুত করতে চাই।


8
আমি ১০০% নিশ্চিত নই তবে আমি বিশ্বাস করি না যে .open()পুরো ফাইলটি মেমরির মধ্যে পড়ে ... (এটিই .load()) যা করে - যতদূর আমি জানি - এটি যতটা ব্যবহার করে তত ভালPIL
জোন ক্লিমেন্টস

5
এমনকি যদি আপনি মনে করেন যে আপনার কোনও ফাংশন রয়েছে যা কেবল চিত্র শিরোনামের তথ্যটি পড়ে, ফাইল সিস্টেম রিডহেড কোডটি এখনও পুরো চিত্রটি লোড করতে পারে। আপনার অ্যাপ্লিকেশনটির প্রয়োজন না হলে পারফরম্যান্স নিয়ে উদ্বেগ অনুচিত হয় od
সম্পূর্ণ

1
আমি আপনার উত্তর সম্পর্কে দৃ convinced় হয়ে উঠলাম। ধন্যবাদ @ জিনক্রিমেন্টস এবং পুরোপুরি
সামি এ। হাইজা

9
pmapএকটি প্রক্রিয়া দ্বারা ব্যবহৃত মেমরি নিরীক্ষণ করতে একটি দ্রুত মেমরি পরীক্ষা আমাকে দেখায় যে সত্যই PILমেমরিতে পুরো চিত্রটি লোড করে না।
ভিনসেন্ট নিভোলিয়ার্স

উত্তর:


63

মন্তব্যগুলি ইঙ্গিত করে যে, কল করার সময় পিআইএল চিত্রটি মেমরিতে লোড করে না .open। দস্তাবেজের দিকে তাকিয়ে PIL 1.1.7, ডক্টরসিং এর জন্য .openবলেছেন:

def open(fp, mode="r"):
    "Open an image file, without loading the raster data"

উত্সটিতে কয়েকটি ফাইল অপারেশন রয়েছে যেমন:

 ...
 prefix = fp.read(16)
 ...
 fp.seek(0)
 ...

তবে এগুলি পুরো ফাইলটি খুব কমই পড়া বোঝায়। আসলে .openসাফল্যের সাথে একটি ফাইল অবজেক্ট এবং ফাইলের নাম দেয় returns দস্তাবেজগুলি অতিরিক্তভাবে বলে:

খুলুন (ফাইল, মোড = "আর")

প্রদত্ত চিত্র ফাইলটি খোলে এবং সনাক্ত করে।

এটি একটি অলস অপারেশন; এই ফাংশনটি ফাইলটি সনাক্ত করে তবে যতক্ষণ না আপনি তথ্য প্রক্রিয়াকরণের চেষ্টা করবেন (বা লোড পদ্ধতিতে কল করুন ) প্রকৃত চিত্রের ফাইলটি ফাইল থেকে পড়ে না ।

আরও গভীর খনন করা, আমরা দেখতে পাই যে .openকলগুলি _openযা কোনও চিত্র-ফর্ম্যাট নির্দিষ্ট ওভারলোড। প্রতিটি বাস্তবায়নের জন্য _openএকটি নতুন ফাইলে পাওয়া যাবে, যেমন। .jpeg ফাইল রয়েছে JpegImagePlugin.py। এর গভীরতার সাথে এক এটি তাকান।

এখানে জিনিসগুলি কিছুটা কৃপণ বলে মনে হচ্ছে, এর মধ্যে একটি অসীম লুপ রয়েছে যা জেপিগ চিহ্নিতকারীটি খুঁজে পাওয়ার পরে ভেঙে যায়:

    while True:

        s = s + self.fp.read(1)
        i = i16(s)

        if i in MARKER:
            name, description, handler = MARKER[i]
            # print hex(i), name, description
            if handler is not None:
                handler(self, i)
            if i == 0xFFDA: # start of scan
                rawmode = self.mode
                if self.mode == "CMYK":
                    rawmode = "CMYK;I" # assume adobe conventions
                self.tile = [("jpeg", (0,0) + self.size, 0, (rawmode, ""))]
                # self.__offset = self.fp.tell()
                break
            s = self.fp.read(1)
        elif i == 0 or i == 65535:
            # padded marker or junk; move on
            s = "\xff"
        else:
            raise SyntaxError("no marker found")

দেখে মনে হচ্ছে এটি যদি বিকৃত হয় তবে এটি পুরো ফাইলটি পড়তে পারে । যদি এটি তথ্য চিহ্নিতকারী ঠিক আছে তবে এটি খুব তাড়াতাড়ি ছড়িয়ে পড়ে। ফাংশনটি handlerশেষ পর্যন্ত সেট করে self.sizeযা চিত্রের মাত্রা dimen


1
সত্য যথেষ্ট, কিন্তু আছে openপেতে আকার ইমেজ বা যে একটি অলস অপারেশন করার ইচ্ছে? এবং যদি এটি অলস হয় তবে এটি একই সাথে চিত্রের ডেটা পড়তে পারে?
মার্ক মুক্তিদান

ডক লিঙ্কটি পিআইএল থেকে একটি কাঁটাচামচকে নির্দেশ করে। তবে ওয়েবে আমি অফিসিয়াল ডক লিঙ্কটি খুঁজে পাচ্ছি না। কেউ যদি এটি মন্তব্য হিসাবে পোস্ট করে আমি উত্তর আপডেট করব। উদ্ধৃতিটি ফাইলটিতে পাওয়া যাবে Docs/PIL.Image.html
26:53

@ মার্করানসম আমি আপনার প্রশ্নের উত্তর দেওয়ার চেষ্টা করেছি, তবে এটি 100% নিশ্চিত হওয়ার মতো বলে মনে হচ্ছে যে প্রতিটি চিত্র-নির্দিষ্টকরণের বাস্তবায়নে আমাদের ডুব দিতে হবে। .jpegবিন্যাস যতদিন দেখে ঠিক মনে হচ্ছে যেমন হেডার পাওয়া যায়।
লাগানো

@ হুকড: এটি দেখার জন্য আপনাকে অনেক ধন্যবাদ। আমি স্বীকার করি যে আপনি সঠিক বলেছেন যদিও আমি নীচে পাওলো এর পরিবর্তে ন্যূনতম সমাধানটি পছন্দ করি (যদিও ন্যায্য হলেও ওপি পিআইএল নির্ভরতা এড়ানোর জন্য উল্লেখ করেনি)
অ্যালেক্স ফ্লিন্ট

@ অ্যালেক্সফ্লিন্ট কোনও সমস্যা নেই, কোডটি ঘেউ ঘেউ করা মজাদার। আমি বলব যে পাওলো তার অনুগ্রহ অর্জন করেছে, এটি একটি দুর্দান্ত স্নিপেট তিনি সেখানে আপনার জন্য লিখেছিলেন।
হুকড হয়েছে

88

আপনি যদি চিত্রের বিষয়বস্তুগুলি সম্পর্কে চিন্তা না করেন তবে পিআইএল সম্ভবত একটি ওভারকিল।

আমি পাইথন ম্যাজিক মডিউলটির আউটপুট পার্স করার পরামর্শ দিচ্ছি:

>>> t = magic.from_file('teste.png')
>>> t
'PNG image data, 782 x 602, 8-bit/color RGBA, non-interlaced'
>>> re.search('(\d+) x (\d+)', t).groups()
('782', '602')

এটি লিবেমজিকের চারপাশে একটি মোড়ক যা কোনও ফাইল টাইপের স্বাক্ষর সনাক্ত করার জন্য যতটা সম্ভব বাইটস পড়ে।

লিপির প্রাসঙ্গিক সংস্করণ:

https://raw.githubusercontent.com/scardine/image_size/master/get_image_size.py

[হালনাগাদ]

হুম, দুর্ভাগ্যক্রমে, যখন জেপিগগুলিতে প্রয়োগ করা হয়, উপরেরটি "'জেপিইজি চিত্র ডেটা দেয়, এক্সআইএফ স্ট্যান্ডার্ড 2.21'" দেয়। কোন চিত্র আকার! - অ্যালেক্স ফ্লিন্ট

জেপিগের মতো মনে হয় যাদু-প্রতিরোধী। :-)

আমি দেখতে পাচ্ছি কেন: জেপিইজি ফাইলগুলির জন্য চিত্রের মাত্রা পেতে, আপনাকে লিবারমাজিক পড়ার চেয়ে বেশি বাইট পড়তে হতে পারে।

আমার আস্তিনগুলি ঘূর্ণিত করল এবং এটি খুব অনাকাঙ্ক্ষিত স্নিপেট নিয়ে এসেছিল (এটি গিটহাব থেকে পান) যাতে তৃতীয় পক্ষের মডিউলগুলির প্রয়োজন হয় না।

দেখো মা!  কোন ডিপ!

#-------------------------------------------------------------------------------
# Name:        get_image_size
# Purpose:     extract image dimensions given a file path using just
#              core modules
#
# Author:      Paulo Scardine (based on code from Emmanuel VAÏSSE)
#
# Created:     26/09/2013
# Copyright:   (c) Paulo Scardine 2013
# Licence:     MIT
#-------------------------------------------------------------------------------
#!/usr/bin/env python
import os
import struct

class UnknownImageFormat(Exception):
    pass

def get_image_size(file_path):
    """
    Return (width, height) for a given img file content - no external
    dependencies except the os and struct modules from core
    """
    size = os.path.getsize(file_path)

    with open(file_path) as input:
        height = -1
        width = -1
        data = input.read(25)

        if (size >= 10) and data[:6] in ('GIF87a', 'GIF89a'):
            # GIFs
            w, h = struct.unpack("<HH", data[6:10])
            width = int(w)
            height = int(h)
        elif ((size >= 24) and data.startswith('\211PNG\r\n\032\n')
              and (data[12:16] == 'IHDR')):
            # PNGs
            w, h = struct.unpack(">LL", data[16:24])
            width = int(w)
            height = int(h)
        elif (size >= 16) and data.startswith('\211PNG\r\n\032\n'):
            # older PNGs?
            w, h = struct.unpack(">LL", data[8:16])
            width = int(w)
            height = int(h)
        elif (size >= 2) and data.startswith('\377\330'):
            # JPEG
            msg = " raised while trying to decode as JPEG."
            input.seek(0)
            input.read(2)
            b = input.read(1)
            try:
                while (b and ord(b) != 0xDA):
                    while (ord(b) != 0xFF): b = input.read(1)
                    while (ord(b) == 0xFF): b = input.read(1)
                    if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
                        input.read(3)
                        h, w = struct.unpack(">HH", input.read(4))
                        break
                    else:
                        input.read(int(struct.unpack(">H", input.read(2))[0])-2)
                    b = input.read(1)
                width = int(w)
                height = int(h)
            except struct.error:
                raise UnknownImageFormat("StructError" + msg)
            except ValueError:
                raise UnknownImageFormat("ValueError" + msg)
            except Exception as e:
                raise UnknownImageFormat(e.__class__.__name__ + msg)
        else:
            raise UnknownImageFormat(
                "Sorry, don't know how to get information from this file."
            )

    return width, height

[২০১৮ আপডেট করুন]

একটি মরিচা বাস্তবায়ন দেখুন: https://github.com/scardine/imsz


3
@ এজেইএইচডেনবার্গ উপরের সংস্করণটির পরে মন্তব্যে আমি চ্যানেলের সংখ্যা পুনরুদ্ধার করার ক্ষমতা (বিভ্রান্তি / বিট গভীরতা না হওয়ার জন্য ) যুক্ত করেছিলাম
গ্রেগ ক্রমিদা

2
দুর্দান্ত জিনিস। আমি গিটহাব প্রকল্পে বিটম্যাপের জন্য সমর্থন যোগ করেছি। ধন্যবাদ!
ম্যালার্ড

2
দ্রষ্টব্য: বর্তমান সংস্করণটি আমার পক্ষে কাজ করে না। @ পাওলোস্কার্ডিনের github.com/scardine/image_size
ডঙ্কমাস্টারডান

2
পান UnicodeDecodeError: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byteMacOS এর, উপর python3 উপর data = input.read(25), fileইমেজ দেয়PNG image data, 720 x 857, 8-bit/color RGB, non-interlaced
mrgloom

3
Raw.githubusercontent.com/scardine/image_size/master/… কাজ করে কোড মনে হচ্ছে ।
mrgloom

24

পাইপিতে একটি প্যাকেজ রয়েছে imagesizeযা বর্তমানে আমার পক্ষে কাজ করে, যদিও এটি দেখতে খুব সক্রিয় বলে মনে হচ্ছে না।

ইনস্টল করুন:

pip install imagesize

ব্যবহার:

import imagesize

width, height = imagesize.get("test.png")
print(width, height)

হোমপেজ: https://github.com/shibukawa/imagesize_py py

পিপিআই: https://pypi.org/project/imagesize/


3
সময়সীমার দ্বারা প্রকৃত চিত্রের আকার পেতে আমি গতির ইমেজসাইজেট, ম্যাজিক.ফ্রম_ফায়াল এবং পিআইএল চিত্রটি তুলনা করেছি। ফলাফলগুলি দেখিয়েছিল যে গতি ইমেজসাইজ.জেট (0.019s)> পিআইএল (0.104s)> রেজেক্স (0.1699s) সহ যাদু।
রায়ানলিউ

9

আমি প্রায়শই ইন্টারনেটে চিত্রের আকার আনয়ন করি। অবশ্যই, আপনি ছবিটি ডাউনলোড করতে পারবেন না এবং তারপরে তথ্য পার্স করতে লোড করতে পারবেন। এটা খুব সময়সাপেক্ষ। আমার পদ্ধতিটি হ'ল ছবিকে একটি চিত্র ধারককে খাওয়ানো এবং এটি প্রতিবার চিত্রটি পার্স করতে পারে কিনা তা পরীক্ষা করা। যখন আমি চাই তথ্যগুলি পাই তখন লুপটি থামান।

আমি আমার কোডের মূলটি বের করে এনে স্থানীয় ফাইলগুলি সংশ্লেষ করতে সংশোধন করেছি।

from PIL import ImageFile

ImPar=ImageFile.Parser()
with open(r"D:\testpic\test.jpg", "rb") as f:
    ImPar=ImageFile.Parser()
    chunk = f.read(2048)
    count=2048
    while chunk != "":
        ImPar.feed(chunk)
        if ImPar.image:
            break
        chunk = f.read(2048)
        count+=2048
    print(ImPar.image.size)
    print(count)

আউটপুট:

(2240, 1488)
38912

আসল ফাইলের আকার 1,543,580 বাইট এবং আপনি কেবলমাত্র চিত্রের আকার পেতে 38,912 বাইট পড়েন। আশা করি এটি সাহায্য করবে।


1

ইউনিক্স সিস্টেমে এটি করার আরও একটি ছোট উপায়। এটি নির্ভর করে যে আউটপুটটির বিষয়ে fileআমি নিশ্চিত নই যে সমস্ত সিস্টেমে মানকযুক্ত। এটি সম্ভবত উত্পাদন কোডে ব্যবহার করা উচিত নয়। তাছাড়া বেশিরভাগ জেপিইজিগুলি চিত্রের আকারের প্রতিবেদন করে না।

import subprocess, re
image_size = list(map(int, re.findall('(\d+)x(\d+)', subprocess.getoutput("file " + filename))[-1]))

দেয়IndexError: list index out of range
mrgloom

0

এই উত্তরের আরও একটি ভাল রেজোলিউশন রয়েছে, তবে পিজিএম ফর্ম্যাটটি অনুপস্থিত । এই উত্তরটি পিজিএম সমাধান করেছে । এবং আমি বিএমপি যোগ করি ।

কোডগুলি নীচে রয়েছে

import struct, imghdr, re, magic

def get_image_size(fname):
    '''Determine the image type of fhandle and return its size.
    from draco'''
    with open(fname, 'rb') as fhandle:
        head = fhandle.read(32)
        if len(head) != 32:
            return
        if imghdr.what(fname) == 'png':
            check = struct.unpack('>i', head[4:8])[0]
            if check != 0x0d0a1a0a:
                return
            width, height = struct.unpack('>ii', head[16:24])
        elif imghdr.what(fname) == 'gif':
            width, height = struct.unpack('<HH', head[6:10])
        elif imghdr.what(fname) == 'jpeg':
            try:
                fhandle.seek(0) # Read 0xff next
                size = 2
                ftype = 0
                while not 0xc0 <= ftype <= 0xcf:
                    fhandle.seek(size, 1)
                    byte = fhandle.read(1)
                    while ord(byte) == 0xff:
                        byte = fhandle.read(1)
                    ftype = ord(byte)
                    size = struct.unpack('>H', fhandle.read(2))[0] - 2
                # We are at a SOFn block
                fhandle.seek(1, 1)  # Skip `precision' byte.
                height, width = struct.unpack('>HH', fhandle.read(4))
            except Exception: #IGNORE:W0703
                return
        elif imghdr.what(fname) == 'pgm':
            header, width, height, maxval = re.search(
                b"(^P5\s(?:\s*#.*[\r\n])*"
                b"(\d+)\s(?:\s*#.*[\r\n])*"
                b"(\d+)\s(?:\s*#.*[\r\n])*"
                b"(\d+)\s(?:\s*#.*[\r\n]\s)*)", head).groups()
            width = int(width)
            height = int(height)
        elif imghdr.what(fname) == 'bmp':
            _, width, height, depth = re.search(
                b"((\d+)\sx\s"
                b"(\d+)\sx\s"
                b"(\d+))", str).groups()
            width = int(width)
            height = int(height)
        else:
            return
        return width, height

imghdrতবে কিছু জেপিগগুলি বেশ খারাপভাবে পরিচালনা করে।
মার্টিक्सी
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.