วิธีตรวจสอบว่าไฟล์เป็นไฟล์รูปภาพที่ถูกต้องหรือไม่?


105

ฉันกำลังใช้ PIL

from PIL import Image
try:
    im=Image.open(filename)
    # do stuff
except IOError:
    # filename not an image file

อย่างไรก็ตามแม้ว่าจะครอบคลุมกรณีส่วนใหญ่อย่างเพียงพอ แต่ก็ไม่พบไฟล์ภาพบางไฟล์เช่น xcf, svg และ psd ไฟล์ Psd แสดงข้อยกเว้น OverflowError

มีบางครั้งที่ฉันสามารถรวมไว้ด้วยได้หรือไม่?


21
ไม่ใช่เรื่องปกติโดยเฉพาะอย่างยิ่งในการปิดรายการที่ซ้ำกันในภาษาต่างๆ หากคุณไม่พบคำถาม Python อื่น ๆ โดยปล่อยให้เปิดไว้เนื่องจากอาจมีวิธีแก้ปัญหาเฉพาะของ Python ที่ผู้คนต้องการโพสต์ซึ่งไม่ตรงกับคำถามที่คุณโพสต์
Paolo Bergantino

ใช่ก่อนอื่นฉันหวังเป็นอย่างยิ่งว่าจะมี python lib ที่ฉันไม่รู้เกี่ยวกับ: P จากนั้นเมื่อเบ็นชี้ให้เห็นเพียงแค่ตัวเลขวิเศษไม่สามารถตรวจสอบภาพทั้งหมดได้
Sujoy

@Sujoy การตรวจสอบความถูกต้องของภาพทั้งหมดแทบจะเป็นไปไม่ได้เว้นแต่คุณจะมีสำเนาอยู่แล้วเนื่องจากคอมพิวเตอร์ไม่สามารถบอกความแตกต่างระหว่างพิกเซลสีที่ถูกต้องและชุด 1s และ 0 ที่อ่านไม่ออกตราบใดที่การควบคุมทั้งหมด (เลขวิเศษ) ถูกต้อง
DevinB

@devinb ตกลงฉันจะได้รับตัวเลขวิเศษและทำมันให้สำเร็จเว้นแต่จะมีคนอื่นมาเรียกร้องให้ refactor ดีกว่า :)
Sujoy

xcf และ psd ไม่ใช่รูปภาพจริงๆเป็นไฟล์โปรเจ็กต์ที่มีรูปภาพ (มักเป็นจำนวนมาก) ... คุณอาจสร้างกรณีสำหรับ svg ได้
mgalgs

คำตอบ:


11

หลายครั้งที่ตัวอักษรคู่แรกจะเป็นตัวเลขมหัศจรรย์สำหรับไฟล์รูปแบบต่างๆ คุณสามารถตรวจสอบสิ่งนี้เพิ่มเติมจากการตรวจสอบข้อยกเว้นด้านบน


10
นั่นจะไม่เพียงพอหากเขาทดสอบภาพที่ "ถูกต้อง" จริงๆ การมีหมายเลขวิเศษไม่ได้รับประกันว่าไฟล์จะไม่ถูกตัดทอนตัวอย่างเช่น
Ben Blank

1
คำแนะนำที่ดีตอนนี้ฉันแค่ต้องหาว่าตัวเลขเหล่านั้นคืออะไร ขอบคุณ :)
Sujoy

@ เบ็นอุ๊ยฉันยังไม่ได้คิดถึงเรื่องนั้น นั่นเป็นจุดที่ดีจริงๆ
Sujoy

@ เบ็นคุณคิดว่าไลบรารีจะอนุมานได้อย่างไรว่าไฟล์ถูกตัดทอน?
DevinB

6
@ Ben Blank: จริง แต่การแก้ปัญหา 99% มักจะดีกว่าแล้วไม่แก้เลย
Brian R.Bondy

206

ฉันเพิ่งพบโมดูลimghdr ในตัว จากเอกสาร python:

โมดูล imghdr กำหนดประเภทของรูปภาพที่อยู่ในไฟล์หรือสตรีมไบต์

นี่คือวิธีการทำงาน:

>>> import imghdr
>>> imghdr.what('/tmp/bass')
'gif'

การใช้โมดูลนั้นดีกว่าการใช้ฟังก์ชันที่คล้ายกันซ้ำ


2
ใช่ imghdr ใช้ได้กับรูปแบบภาพส่วนใหญ่ แต่ไม่ใช่ทั้งหมด ตามปัญหาเดิมของฉันกับไฟล์ svg, xcf และ psd ซึ่งจะไม่ถูกตรวจพบใน imghdr เช่นกัน
Sujoy

2
คำตอบของคุณดีขึ้นจริงขอบคุณ เหมือนที่คนข้างบนบอก... แต่การแก้ปัญหา 99% มักจะดีขึ้นแล้วไม่แก้เลย ..
RinkyPinku

2
สิ่งที่ควรทราบ: imghdr.what(path)ส่งคืนNoneหากpathไม่รู้จักประเภทไฟล์ภาพ รายการของได้รับการยอมรับในปัจจุบันชนิดของภาพ: RGB , GIF , PBM , PGM , ppm , TIFF , Rast , XBM , JPEG , BMP , PNG , webp , EXR
patryk.beza

1
ระวัง! hdr ที่ถูกต้องไม่ได้หมายถึงภาพที่ถูกต้อง (เช่นไบต์ของภาพอาจถูกรบกวน!)
Filippo Mazza

1
ตามความคิดเห็นของ @FilippoMazza ฉันสามารถยืนยันได้ว่าภาพที่ไม่ดีที่ถูกตัดออกระหว่างการถ่ายโอนสามารถผ่านการทดสอบนี้ได้ แต่จะแตกเมื่อ PIL พยายามอ่าน
kevinmicke

47

นอกจากสิ่งที่ Brian แนะนำแล้วคุณยังสามารถใช้วิธีการตรวจสอบของ PIL เพื่อตรวจสอบว่าไฟล์เสียหรือไม่

im.verify ()

พยายามตรวจสอบว่าไฟล์เสียหรือไม่โดยไม่ได้ถอดรหัสข้อมูลรูปภาพจริงๆ หากวิธีนี้พบปัญหาใด ๆ จะมีข้อยกเว้นที่เหมาะสม วิธีนี้ใช้ได้กับรูปภาพที่เพิ่งเปิดใหม่เท่านั้น หากโหลดรูปภาพแล้วผลลัพธ์จะไม่ได้กำหนด นอกจากนี้หากคุณต้องการโหลดภาพหลังจากใช้วิธีนี้คุณต้องเปิดไฟล์รูปภาพอีกครั้ง คุณลักษณะ


ปัญหาหลักคือไฟล์ svg, xcf และ psd ไม่สามารถเปิดด้วย Image.open () ได้ดังนั้นจึงไม่มีโอกาสยืนยันด้วย im.verify ()
Sujoy

16
พระเจ้าของฉันเอกสาร PIL แย่มาก "ข้อยกเว้นที่เหมาะสม" คืออะไรกันแน่?
Timmmm

นี่คือการเชื่อมโยงไปยังเอกสารหมอนสำหรับ Image.verify () น่าเสียดายที่มันไม่ดีไปกว่านี้และดูเหมือนว่าพวกเขาจะยกย่อหน้าข้างบนโดยไม่ได้เพิ่มอะไรเลย
Two-Bit Alchemist

ฉันเคยเห็นการตรวจสอบการเพิ่ม SyntaxError สำหรับไฟล์ png ที่เสียหาย
Carl

มีวิธีตรวจสอบ "ด้วยการถอดรหัสข้อมูลรูปภาพจริงหรือไม่"
Trevor Boyd Smith

7

นอกจากการPILตรวจสอบรูปภาพแล้วคุณยังสามารถเพิ่มการตรวจสอบนามสกุลไฟล์ได้เช่นนี้:

filename.lower().endswith(('.png', '.jpg', '.jpeg', '.tiff', '.bmp', '.gif'))

โปรดทราบว่าสิ่งนี้จะตรวจสอบว่าชื่อไฟล์มีนามสกุลรูปภาพที่ถูกต้องหรือไม่ แต่ไม่ได้เปิดภาพเพื่อดูว่าเป็นภาพที่ถูกต้องหรือไม่นั่นเป็นเหตุผลที่คุณต้องใช้เพิ่มเติมPILหรือไลบรารีใด ๆ ที่แนะนำในคำตอบอื่น ๆ


จะเกิดอะไรขึ้นถ้านามสกุลไม่ถูกต้องในไฟล์? เช่นไฟล์ข้อความจะถูกบันทึกด้วยนามสกุล. jpg หรือในทางกลับกัน
hafiz031

1
@ hafiz031 เพื่อให้ได้รูปแบบที่แท้จริงคุณสามารถทำได้from PIL import Image img = Image.open(filename) print(img.format)จากนั้นตรวจสอบดังนี้:img.format.lower() in ['png', 'jpg', 'jpeg', 'tiff', 'bmp', 'gif']
tsveti_iko

น่าเสียดายที่สิ่งนี้ไม่ได้ผลสำหรับฉัน มันยังคงระบุภาพที่เสียหายเป็นภาพ JPEG ในที่สุดฉันก็จัดการกรณีนี้ได้ด้วยวิธีนี้ (ฉันใช้ OpenCv): stackoverflow.com/a/63421847/6907424
hafiz031

6

อัปเดต

ฉันยังดำเนินการแก้ปัญหาต่อไปนี้ในสคริปต์ Python ของฉันที่นี่ใน GitHub

ฉันยังตรวจสอบด้วยว่าไฟล์ที่เสียหาย (jpg) มักไม่ใช่ภาพที่ 'เสีย' เช่นไฟล์รูปภาพที่เสียหายบางครั้งยังคงเป็นไฟล์รูปภาพที่ถูกต้องรูปภาพต้นฉบับสูญหายหรือมีการเปลี่ยนแปลง แต่คุณยังสามารถโหลดได้โดยไม่มีข้อผิดพลาด แต่การตัดไฟล์ทำให้เกิดข้อผิดพลาดเสมอ

สิ้นสุดการอัปเดต

คุณสามารถใช้โมดูลPython Pillow (PIL) กับรูปแบบรูปภาพส่วนใหญ่เพื่อตรวจสอบว่าไฟล์นั้นเป็นไฟล์รูปภาพที่ถูกต้องหรือไม่

ในกรณีที่คุณมุ่งเป้าไปที่การตรวจจับภาพที่แตกเช่นกัน @Nadia Alramli แนะนำim.verify()วิธีการนี้อย่างถูกต้องแต่ไม่พบข้อบกพร่องของภาพที่เป็นไปได้ทั้งหมดเช่นim.verifyตรวจไม่พบภาพที่ถูกตัดทอน (ซึ่งผู้ชมส่วนใหญ่มักจะโหลดด้วยพื้นที่สีเทา)

หมอนสามารถตรวจจับข้อบกพร่องประเภทนี้ได้เช่นกัน แต่คุณต้องใช้การปรับแต่งภาพหรือการถอดรหัส / การเข้ารหัสภาพหรือเพื่อเรียกใช้การตรวจสอบ สุดท้ายฉันขอแนะนำให้ใช้รหัสนี้:

try:
  im = Image.load(filename)
  im.verify() #I perform also verify, don't know if he sees other types o defects
  im.close() #reload is necessary in my case
  im = Image.load(filename) 
  im.transpose(PIL.Image.FLIP_LEFT_RIGHT)
  im.close()
except: 
  #manage excetions here

ในกรณีที่ภาพมีข้อบกพร่องรหัสนี้จะยกข้อยกเว้น โปรดพิจารณาว่า im.verify เร็วกว่าการปรับแต่งภาพประมาณ 100 เท่า (และฉันคิดว่าการพลิกเป็นหนึ่งในการแปลงที่ถูกกว่า) ด้วยรหัสนี้คุณจะตรวจสอบชุดภาพที่ความเร็วประมาณ 10 MBytes / วินาทีด้วย Pillow มาตรฐานหรือ 40 MBytes / วินาทีพร้อมโมดูล Pillow-SIMD (CPU 2.5Ghz x86_64 ที่ทันสมัย)

สำหรับรูปแบบอื่น ๆpsd , xcf , .. คุณสามารถใช้Imagemagick wrapper Wandรหัสจะเป็นดังนี้:

im = wand.image.Image(filename=filename)
temp = im.flip;
im.close()

แต่จากการทดลองของฉัน Wand ตรวจไม่พบภาพที่ถูกตัดทอนฉันคิดว่ามันโหลดส่วนที่ขาดเป็นพื้นที่สีเทาโดยไม่ต้องแจ้ง

ฉันขอแดงว่าImagemagickมีคำสั่งภายนอกที่ระบุว่าสามารถทำให้งานได้ แต่ฉันไม่พบวิธีเรียกใช้ฟังก์ชันนั้นโดยใช้โปรแกรมและฉันไม่ได้ทดสอบเส้นทางนี้

ฉันขอแนะนำให้ทำการตรวจสอบเบื้องต้นเสมอตรวจสอบขนาดไฟล์ไม่ให้เป็นศูนย์ (หรือเล็กมาก) เป็นแนวคิดที่ถูกมาก:

statfile = os.stat(filename)
filesize = statfile.st_size
if filesize == 0:
  #manage here the 'faulty image' case

5

บน Linux คุณสามารถใช้ python-magic ( http://pypi.python.org/pypi/python-magic/0.1 ) ซึ่งใช้ libmagic เพื่อระบุรูปแบบไฟล์

AFAIK, libmagic จะตรวจสอบไฟล์และพยายามบอกคุณเกี่ยวกับมันมากกว่าแค่รูปแบบเช่นขนาดบิตแมปเวอร์ชันรูปแบบ ฯลฯ ดังนั้นคุณอาจเห็นว่านี่เป็นการทดสอบ "ความถูกต้อง" เพียงผิวเผิน

สำหรับคำจำกัดความอื่น ๆ ของ "ถูกต้อง" คุณอาจต้องเขียนแบบทดสอบของคุณเอง


5

คุณสามารถใช้การผูก Python กับ libmagic, python-magicจากนั้นตรวจสอบประเภท mime สิ่งนี้จะไม่บอกคุณว่าไฟล์เสียหายหรือไม่เสียหาย แต่ควรจะสามารถระบุได้ว่าเป็นภาพประเภทใด


3

ฉันไม่รู้เกี่ยวกับด้านในของ psd แต่ฉันแน่ใจว่าแท้จริงแล้ว svg ไม่ใช่ไฟล์ภาพต่อ se - มันขึ้นอยู่กับ xml ดังนั้นโดยพื้นฐานแล้วคือ a ไฟล์ข้อความธรรมดา


อ๊ะคุณพูดถูก มันคือ xml อย่างไรก็ตามมีข้อมูลรูปภาพบางส่วนฝังอยู่
Sujoy

2

ทางเลือกหนึ่งคือการใช้filetypeแพ็คเกจ

การติดตั้ง

python -m pip install filetype

ข้อดี

  1. รวดเร็ว: ทำงานได้โดยการโหลดรูปภาพสองสามไบต์แรก ( ตรวจสอบหมายเลขวิเศษ )
  2. รองรับประเภทละครใบ้ที่แตกต่างกัน: รูปภาพ, วิดีโอ, แบบอักษร, เสียง, ที่เก็บถาวร

ตัวอย่างโซลูชัน

import filetype

filename = "/path/to/file.jpg"

if filetype.image(filename):
    print(f"{filename} is a valid image...")
elif filetype.video(filename):
    print(f"{filename} is a valid video...")

ข้อมูลเพิ่มเติมเกี่ยวกับ repo อย่างเป็นทางการ: https://github.com/h2non/filetype.py


1

การตรวจสอบนามสกุลไฟล์เป็นสิ่งที่ยอมรับได้หรือคุณกำลังพยายามยืนยันว่าข้อมูลนั้นเป็นไฟล์รูปภาพหรือไม่

หากคุณสามารถตรวจสอบนามสกุลของไฟล์ได้ว่านิพจน์ทั่วไปหรือการเปรียบเทียบแบบธรรมดาสามารถตอบสนองความต้องการได้


เพียงแค่ตรวจสอบส่วนขยายจะไม่เพียงพอเนื่องจากสามารถเปลี่ยนชื่อไฟล์ txt เป็น jpg หรืออะไรก็ได้ ฉันเดาว่าถ้าฉันไม่พบวิธีแก้ปัญหาฉันจะใช้การตรวจสอบส่วนขยายสำหรับ xcf และ svg เท่านั้น
Sujoy

เข้าใจได้ฉันแค่หวังว่าจะได้รับคำชี้แจงก่อนที่ฉันจะดำเนินการต่อเพื่อคิดค้นวิธีแก้ปัญหาที่อาจเหมาะกับความต้องการของคุณ ขอบคุณ!
doomspork

-1
format = [".jpg",".png",".jpeg"]
 for (path,dirs,files) in os.walk(path):
     for file in files:
         if file.endswith(tuple(format)):
             print(path)
             print ("Valid",file)
         else:
             print(path)
             print("InValid",file)

รหัสของคุณมีปัญหาในการเยื้องและทำงานไม่ถูกต้อง นอกจากนี้ให้พิจารณาเพิ่มคำอธิบายเกี่ยวกับสาเหตุและวิธีแก้ปัญหาของโค้ด คำตอบที่ใช้รหัสเท่านั้นโดยไม่เป็นประโยชน์สำหรับผู้อ่านในอนาคตที่มาที่นี่
Tomerikoo

ที่นี่เราได้ใช้วิธี Agrparser
rObinradOO
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.