[PYTHON] Numpy 및 16 비트 PGM
PYTHONNumpy 및 16 비트 PGM
numpy로 파이썬에서 16 비트 PGM 이미지를 읽기위한 효율적이고 명확한 방법은 무엇입니까?
PIL 버그로 인해 PIL을 사용하여 16 비트 PGM 이미지를로드 할 수 없습니다. 다음 코드를 사용하여 헤더를 읽을 수 있습니다.
dt = np.dtype([('type', 'a2'),
('space_0', 'a1', ),
('x', 'a3', ),
('space_1', 'a1', ),
('y', 'a3', ),
('space_2', 'a1', ),
('maxval', 'a5')])
header = np.fromfile( 'img.pgm', dtype=dt )
print header
올바른 데이터를 인쇄합니다. ( 'P5', '', '640', '', '480', '', '65535') 그러나 나는 가장 좋은 방법이 아닌 느낌을 가지고 있습니다. 그 외에도 크기 (헤더)가 16 비트 인 y (이 경우 640x480)의 다음 x 데이터를 읽는 방법을 파악하는 방법에 문제가 있습니다.
수정 : 이미지 추가
이미지를 읽고 표시하는 MATLAB 코드는 다음과 같습니다.
I = imread('foo.pgm');
imagesc(I);
그리고 다음과 같이 보입니다.
해결법
-
==============================
1.
import re import numpy def read_pgm(filename, byteorder='>'): """Return image data from a raw PGM file as numpy array. Format specification: http://netpbm.sourceforge.net/doc/pgm.html """ with open(filename, 'rb') as f: buffer = f.read() try: 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)*)", buffer).groups() except AttributeError: raise ValueError("Not a raw PGM file: '%s'" % filename) return numpy.frombuffer(buffer, dtype='u1' if int(maxval) < 256 else byteorder+'u2', count=int(width)*int(height), offset=len(header) ).reshape((int(height), int(width))) if __name__ == "__main__": from matplotlib import pyplot image = read_pgm("foo.pgm", byteorder='<') pyplot.imshow(image, pyplot.cm.gray) pyplot.show()
-
==============================
2.PGM 형식에 익숙하지 않지만 일반적으로 numpy.fromfile을 사용합니다. fromfile은 전달 된 파일 포인터가있는 위치에서 시작하므로 헤더의 끝까지 간단히 검색 (또는 읽음) 한 다음 fromfile을 사용하여 나머지를 읽을 수 있습니다.
PGM 형식에 익숙하지 않지만 일반적으로 numpy.fromfile을 사용합니다. fromfile은 전달 된 파일 포인터가있는 위치에서 시작하므로 헤더의 끝까지 간단히 검색 (또는 읽음) 한 다음 fromfile을 사용하여 나머지를 읽을 수 있습니다.
다음 (infile) 대신 infile.readline ()을 사용해야합니다.
import numpy as np with open('foo.pgm', 'r') as infile: header = infile.readline() width, height, maxval = [int(item) for item in header.split()[1:]] image = np.fromfile(infile, dtype=np.uint16).reshape((height, width))
부수적으로 메모에서 가리키는 "foo.pgm"파일이 헤더의 잘못된 행 수를 지정하는 것으로 보입니다.
잠재적으로 그 문제가있는 많은 파일을 읽는다면 배열에 0을 덧붙이거나 자르면됩니다.
import numpy as np with open('foo.pgm', 'r') as infile: header = next(infile) width, height, maxval = [int(item) for item in header.split()[1:]] image = np.fromfile(infile, dtype=np.uint16) if image.size < width * height: pad = np.zeros(width * height - image.size, dtype=np.uint16) image = np.hstack([image, pad]) if image.size > width * height: image = image[:width * height] image = image.reshape((height, width))
-
==============================
3.실제로, 헤더 뒤의 '문자열'은 파일의 바이너리입니다. 나는 아래에서 그것을 해결했다 : (ndarray : [2047 2047 2047 ..., 540 539 539])하지만 또 다른 문제가있다 : 파일이 충분히 길지 않다. 640 * 480 대신 289872 숫자 만 계산합니다 ...
실제로, 헤더 뒤의 '문자열'은 파일의 바이너리입니다. 나는 아래에서 그것을 해결했다 : (ndarray : [2047 2047 2047 ..., 540 539 539])하지만 또 다른 문제가있다 : 파일이 충분히 길지 않다. 640 * 480 대신 289872 숫자 만 계산합니다 ...
나는 그것을위한 수업을 만들어서 나의 exageration을 대단히 유감스럽게 생각한다. ..
import numpy as np import Image class PGM(object): def __init__(self, filepath): with open(filepath) as f: # suppose all header info in first line: info = f.readline().split() self.type = info[0] self.width, self.height, self.maxval = [int(v) for v in info[1:]] size = self.width * self.height lines = f.readlines() dt = [np.int8, np.int16][self.maxval > 255] try: # this will work if lines are integers separated by e.g. spaces self.data = np.array([l.split() for l in lines], dtype=dt).T except ValueError: # data is binary data = np.fromstring(lines[0], dtype=dt) if data.size < size: # this is the case for the 'db.tt/phaR587 (foo.pgm)' #raise ValueError('data binary string probably uncomplete') data = np.hstack((data, np.zeros(size-data.size))) self.data = data[:size].reshape((self.width, self.height)) assert (self.width, self.height) == self.data.shape assert self.maxval >= self.data.max() self._img = None def get_img(self): if self._img is None: # only executed once size = (self.width, self.height) mode = 'L' data = self.data self.img = Image.frombuffer(mode, size, data) return self.img Image = property(get_img) mypgm = PGM('foo.pgm') mypgm.Image
편집 : 이미지를 0으로 채우는 조 킹턴의 위대한 아이디어!
-
==============================
4.여기에서 나는 헤더 정보가 공백, 캐리지 리턴 또는 기타로 구분 될 수 있음을 이해합니다. 너의 것을 공백으로 구분하면 (나에게 알리면) 다음과 같이 할 수있다.
여기에서 나는 헤더 정보가 공백, 캐리지 리턴 또는 기타로 구분 될 수 있음을 이해합니다. 너의 것을 공백으로 구분하면 (나에게 알리면) 다음과 같이 할 수있다.
with open('img.pgm') as f: lines = f.readlines() data = np.array([line.split() for line in lines[1:]], dtype=np.int16).T
이제 데이터가 int16 형식의 배열이됩니다!
헤더 정보에 계속 관심이 있다고 가정하면 다음을 수행 할 수 있습니다.
class Header(object): def __init__(self, type, width, height, maxval): self.type = type self.width = int(width) self.height = int(height) self.maxval = int(maxval) h = Header(*lines[0].split()[:4])
읽기 라인에 대해 이미지 데이터를 확인할 수 있습니다.
assert (h.width, h.height) == data.shape assert h.maxval >= data.max()
편집 : 이미지 데이터가 바이너리 인 경우 파일을 'rb'로 열고 헤더 정보 다음부터 읽어야합니다.
import numpy as np def as_array(filepath): f = open(filepath, 'r') w, h = size = tuple(int(v) for v in next(f).split()[1:3]) data_size = w * h * 2 f.seek(0, 2) filesize = f.tell() f.close() i_header_end = filesize - (data_size) f = open(filepath, 'rb') f.seek(i_header_end) buffer = f.read() f.close() # convert binary data to an array of the right shape data = np.frombuffer(buffer, dtype=np.uint16).reshape((w, h)) return data a = as_array('foo.pgm')
-
==============================
5.이에 대해 @ joe-kington이 대답 해 주신 것에 감사드립니다. 해결책은 다음과 같습니다.
이에 대해 @ joe-kington이 대답 해 주신 것에 감사드립니다. 해결책은 다음과 같습니다.
알려진 헤더 길이를 하드 코딩하지 않는 약간의 추가 작업이 있습니다 (17 바이트 이 경우), 헤더에서 결정합니다. PGM 표준에 따르면 헤더는 일반적으로 개행 문자로 끝나지만 공백으로 끝날 수 있습니다. 이 코드는 끝 부분의 delimeter에 개행 문자가 아닌 공백 문자를 사용하는 PGM에서 중단 될 것이라고 생각합니다. 이 경우 헤더 크기는 너비, 높이 및 최대 크기를 포함하는 변수의 크기와 'P5'의 2 바이트와 공백의 4 바이트를 더한 값으로 결정됩니다.
이것이 깨질 수있는 다른 경우는 너비 또는 높이가 int (매우 큰 이미지)보다 큰 경우입니다. 또는 PGM이 16 비트가 아닌 8 비트 (maxval 및 가능한 너비, 높이 및 파일 크기에서 결정될 수 있음) 인 경우
#!/usr/bin/python import numpy as np import matplotlib.pyplot as plt file='foo.pgm' infile = open(file,'r') header = next(infile) width, height, maxval = [int(item) for item in header.split()[1:]] infile.seek(len(header)) image = np.fromfile(infile, dtype=np.uint16).reshape((height, width)) print width, height, maxval plt.figimage(image)
from https://stackoverflow.com/questions/7368739/numpy-and-16-bit-pgm by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] 마샬링 덤프가 더 빨라지고 cPickle이 더 빨리로드됩니다. (0) | 2018.11.14 |
---|---|
[PYTHON] Miniconda에 Jupyter Notebook을 설치하십시오. (0) | 2018.11.14 |
[PYTHON] 파이썬에서 16 진수로 음수 값을 변환하는 방법 (0) | 2018.11.14 |
[PYTHON] 파이썬 팩토리 함수는 클래스와 비교된다. (0) | 2018.11.14 |
[PYTHON] 파이썬 하위 프로세스 타임 아웃? (0) | 2018.11.14 |