Конвертировать .IMG (образ диска Classi c) в .PNG / .JPG в Python - PullRequest
2 голосов
/ 08 марта 2020

У меня есть набор данных из 1 000 000+ файлов .IMG, которые мне нужно преобразовать в формат .PNG / .JPG, чтобы применить CNN для простой задачи классификации.
Я сослался на этот ответ и решение у меня работает частично . Я имею в виду, что некоторые изображения не конвертируются должным образом. Причина, по моему мнению, состоит в том, что некоторые изображения имеют глубину пикселя 16, а некоторые - 8.

for file in fileList:
    rawData = open(file, 'rb').read()
    size = re.search("(LINES              = \d\d\d\d)|(LINES              = \d\d\d)", str(rawData))
    pixelDepth = re.search("(SAMPLE_BITS        = \d\d)|(SAMPLE_BITS        = \d)", str(rawData))
    size = (str(size)[-6:-2])
    pixelDepth = (str(pixelDepth)[-4:-2])
    print(int(size))
    print(int(pixelDepth))
    imgSize = (int(size), int(size))



    img = Image.frombytes('L', imgSize, rawData)
    img.save(str(file)+'.jpg')


Источник данных: NASA Messenger Mission
.IMG-файлов и соответствующих им преобразованных .JPG-файлов


Файлы с глубиной пикселя 8 успешно конвертированы:
enter image description here


Файлы с глубиной пикселя 16 НЕ конвертируются должным образом:
enter image description here

Пожалуйста, дайте мне знать, если есть какая-либо дополнительная информация, которую я должен предоставить.

1 Ответ

3 голосов
/ 09 марта 2020

Надеюсь, из моего другого ответа, здесь , теперь вы лучше понимаете, как отформатированы ваши файлы. Итак, код должен выглядеть примерно так:

#!/usr/bin/env python3

import sys
import re
import numpy as np
from PIL import Image
import cv2

rawData  = open('EW0220137564B.IMG', 'rb').read()
# File size in bytes
fs       = len(rawData)
bitDepth = int(re.search("SAMPLE_BITS\s+=\s+(\d+)",str(rawData)).group(1))
bytespp  = int(bitDepth/8)
height   = int(re.search("LINES\s+=\s+(\d+)",str(rawData)).group(1))
width    = int(re.search("LINE_SAMPLES\s+=\s+(\d+)",str(rawData)).group(1))
print(bitDepth,height,width)

# Offset from start of file to image data - assumes image at tail end of file
offset = fs - (width*height*bytespp)

# Check bitDepth
if bitDepth == 8:
    na = np.frombuffer(rawData, offset=offset, dtype=np.uint8).reshape(height,width)
elif bitDepth == 16:
    dt = np.dtype(np.uint16)
    dt = dt.newbyteorder('>')
    na = np.frombuffer(rawData, offset=offset, dtype=dt).reshape(height,width).astype(np.uint8)
else:
    print(f'ERROR: Unexpected bit depth: {bitDepth}',file=sys.stderr)

# Save either with PIL
Image.fromarray(na).save('result.jpg')
# Or with OpenCV may be faster
cv2.imwrite('result.jpg', na)

Если у вас есть тысячи дел, я бы порекомендовал GNU Parallel , который вы можете легко установить на свой Ma c с homebrew с использованием:

brew install parallel

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

parallel --dry-run script.py {} ::: *.IMG

Для еще больших усилий вы можете сделать это еще быстрее, поместив приведенный выше код в функцию и вызвав функцию для каждого файла, указанного в качестве параметра. Таким образом, вы можете не запускать новый интерпретатор Python для каждого изображения и указывать GNU Parallel на передачу как можно большего количества файлов на каждый вызов вашего сценария, например:

parallel -X --dry-run script.py ::: *.IMG

Структура скрипта выглядит следующим образом:

def processOne(filename):
    open, read, search, extract, save as per my code above

# Main - process all filenames received as parameters
for filename in sys.argv[1:]:
    processOne(filename)
...