Python pgm解析和格式轉換
阿新 • • 發佈:2018-12-19
下載ORL人臉資料庫,發現其影象檔案格式為pgm
,之前也遇到過這種情況,這次仔細分析它的使用,並編寫指令碼用於影象格式之間的轉換
參考:
目錄
PGM
解析
PGM
解析pgm
(行動式灰度圖,Portable Gray Map
)是Netpbm
開源工程設計的一種影象格式,除了pgm
外,還有pbm
,ppm
一個pgm
檔案可以表示一個或多個pgm
影象,其檔案內容如下:
1. A "magic number" for identifying the file type. A pgm image's magic number is the two characters "P5". 2. Whitespace (blanks, TABs, CRs, LFs). 3. A width, formatted as ASCII characters in decimal. 4. Whitespace. 5. A height, again in ASCII decimal. 6. Whitespace. 7. The maximum gray value (Maxval), again in ASCII decimal. Must be less than 65536, and more than zero. 8. A single whitespace character (usually a newline). 9. A raster of Height rows, in order from top to bottom. Each row consists of Width gray values, in order from left to right. Each gray value is a number from 0 through Maxval, with 0 being black and Maxval being white. Each gray value is represented in pure binary by either 1 or 2 bytes. If the Maxval is less than 256, it is 1 byte. Otherwise, it is 2 bytes. The most significant byte is first. 1. 用於識別檔案型別的“幻數”。PGM影象的幻數是兩個字元“P5”。 2. 空格(blanks, TABs, CRs, LFs)。 3. 寬度,格式為ASCII十進位制數字。 4. 空格。 5. 高度,同樣為ASCII十進位制數字。 6. 空格。 7. 最大灰度值(Maxval),同時是ASCII十進位制。範圍為[0,6536]。 8. 單個空白字元(通常是換行符)。 9. 從上到下,從左到右排列灰度值。每個灰度值取值為[0,Maxval],其中0表示黑色,Maxval表示白色。每個灰度值由1個或2個位元組的純二進位制表示。如果最大值小於256,則為1位元組。否則,它是2位元組。最重要的位元組是第一個。
用Notepad++
開啟一個PGM
檔案
P5
92 112
255
01-/19'*515<L[c_PKB6/12+.5=FTi厒n^Qk_P9...
它的幻數是P5
,寬為92
,高為112
,最大值為255
。
Plain PGM
還有其中格式的PGM
檔案,它的幻數是P2
,稱為Plain PGM
,這種格式的變化在於:
1. There is exactly one image in a file. 2. The magic number is P2 instead of P5. 3. Each pixel in the raster is represented as an ASCII decimal number (of arbitrary size). 4. Each pixel in the raster has white space before and after it. There must be at least one character of white space between any two pixels, but there is no maximum. 5. No line should be longer than 70 characters. 1. 檔案中僅有單個影象。 2. 幻數是P2。 3. 柵格中的每個畫素表示為ASCII十進位制數(任意大小)。 4. 光柵中的每個畫素在其前後都有白色空間。在任何兩個畫素之間必須至少有一個空白字元。 5. 沒有一行應該長於70個字元。
示例如下:
P2 # feep.pgm 24 7 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0 0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0 0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0 0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0 0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
為什麼灰度圖會有一個灰度取值兩個位元組?
平常都是在RGB
模式下工作,灰度取值為[0 - 255]
,所以一個位元組就好了
但其實還有更多的灰度級數,比如16
位灰度,那就需要2
個位元組
格式轉換
寫了一個python
程式,可以批量處理,也可以單個影象轉換
# -*- coding: utf-8 -*-
from __future__ import print_function
import cv2
import time
import os
import operator
import numpy as np
import argparse
from PIL import Image
__author__ = 'zj'
image_formats = ['jpg', 'JPG', 'jpeg', 'JPEG', 'png', 'PNG']
def is_pgm_file(in_path):
if not os.path.isfile(in_path):
return False
if in_path is not str and not in_path.endswith('.pgm'):
return False
return True
def convert_pgm_by_PIL(in_path, out_path):
if not is_pgm_file(in_path):
raise Exception("%s 不是一個PGM檔案" % in_path)
# 讀取檔案
im = Image.open(in_path)
im.save(out_path)
def convert_pgm_P5(in_path, out_path):
"""
將pgm檔案轉換成其它影象格式
讀取二進位制檔案,先讀取幻數,再讀取寬和高,以及最大值
:param in_path: 輸入pgm檔案路徑
:param out_path: 輸出檔案路徑
"""
if not is_pgm_file(in_path):
raise Exception("%s 不是一個PGM檔案" % in_path)
with open(in_path, 'rb') as f:
# 讀取兩個位元組 - 幻數,並解碼成字串
magic_number = f.readline().strip().decode('utf-8')
if not operator.eq(magic_number, "P5"):
raise Exception("該影象有誤")
# 讀取高和寬
width, height = f.readline().strip().decode('utf-8').split(' ')
width = int(width)
height = int(height)
# 讀取最大值
maxval = f.readline().strip()
# 每次讀取灰度值的位元組數
if int(maxval) < 256:
one_reading = 1
else:
one_reading = 2
# 建立空白影象,大小為(行,列)=(height, width)
img = np.zeros((height, width))
img[:, :] = [[ord(f.read(one_reading)) for j in range(width)] for i in range(height)]
cv2.imwrite(out_path, img)
print('%s save ok' % out_path)
def convert_pgm_P5_batch(in_dir, out_dir, res_format):
"""
批量轉換PGM檔案
:param in_dir: pgm資料夾路徑
:param out_dir: 輸出資料夾路徑
:param res_format: 結果影象格式
"""
if not os.path.isdir(in_dir):
raise Exception('%s 不是路徑' % in_dir)
if not os.path.isdir(out_dir):
raise Exception('%s 不是路徑' % out_dir)
if not res_format in image_formats:
raise Exception('%s 暫不支援' % res_format)
file_list = os.listdir(in_dir)
for file_name in file_list:
file_path = os.path.join(in_dir, file_name)
# 若為pgm檔案路徑,那麼將其進行格式轉換
if is_pgm_file(file_path):
file_out_path = os.path.join(out_dir, os.path.basename(file_name) + '.' + res_format)
convert_pgm_P5(file_path, file_out_path)
# 若為目錄,則新建結果檔案目錄,遞迴處理
elif os.path.isdir(file_path):
file_out_dir = os.path.join(out_dir, file_name)
if not os.path.exists(file_out_dir):
os.mkdir(file_out_dir)
convert_pgm_P5_batch(file_path, file_out_dir, res_format)
else:
pass
print('batch operation over')
if __name__ == '__main__':
script_start_time = time.time()
parser = argparse.ArgumentParser(description='Format Converter - PGM')
### Positional arguments
### Optional arguments
parser.add_argument('-i', '--input', type=str, help='Path to the pgm file')
parser.add_argument('-o', '--output', type=str, help='Path to the result file')
parser.add_argument('--input_dir', type=str, help='Dir to the pgm files')
parser.add_argument('--output_dir', type=str, help='Dir to the result files')
parser.add_argument('-f', '--format', default='png', type=str, help='result image format')
parser.add_argument('-b', '--batch', action="store_true", default=False, help='Batch processing')
args = vars(parser.parse_args())
# print(args)
in_path = args['input']
out_path = args['output']
isbatch = args['batch']
in_dir = args['input_dir']
out_dir = args['output_dir']
res_format = args['format']
if in_path is not None and out_path is not None:
# 轉換單個pgm檔案格式
convert_pgm_P5(in_path, out_path)
# convert_pgm_by_PIL(in_path, out_path)
elif isbatch:
# 批量轉換
convert_pgm_P5_batch(in_dir, out_dir, res_format)
else:
print('請輸入相應引數')
print('Script took %s seconds.' % (time.time() - script_start_time,))
使用PIL
庫也可以讀取PGM
檔案,然後儲存為其它格式影象,我自己寫了一個解析二進位制檔案的方式,速度比呼叫PIL
庫快大約2.5
倍
轉換單個PGM
檔案:
python PGMConverter.py -i INPUT -o OUTPUT
例如:
python PGMConverter.py -i 1.pgm -o 3.png
轉換整個PGM
資料夾
python PGMConverter.py --batch --input_dir INPUT_DIR --output_dir OUTPUT_DIR -f FORMAT
INPUT_DIR
替換成PGM
資料夾路徑,OUTPUT_DIR
替換成結果檔案路徑(該資料夾需提前新建),FORMAT
替換成結果影象格式
例如:
python PGMConverter.py --batch --input_dir c:\\face\\att_faces --output_dir c:\\face\\att_face_png -f png