2016-03-04 192 views
3

首先,我的問題是How do I convert image to 2-bit per pixel?,不幸的是它的解決方案並不在我的情況下工作,不同的...圖像轉換爲索引2位灰度BMP

我需要將圖像轉換爲每像素2位灰度BMP格式。樣本圖像具有以下屬性:

Color Model: RGB 
Depth: 4 
Is Indexed: 1 
Dimension: 800x600 
Size: 240,070 bytes (4 bits per pixel but only last 2 bits are used to identify the gray scales as 0/1/2/3 in decimal or 0000/0001/0010/0011 in binary, plus 70 bytes BMP metadata or whatever) 

sample

樣品BMP圖像的開始部分的十六進制值: head of sample image

3S的在圖像的開頭表示白色像素。再往下有一些0,1和2秒錶示黑色,深灰色和淺灰色: mid-part of sample image

與下面的命令,

convert pic.png -colorspace gray +matte -depth 2 out.bmp 

我可以得到視覺正確4級灰度圖像,但錯誤的深度或大小每像素:

Color Model: RGB 
Depth: 8 (expect 4) 
Dimension: 800x504 
Size: 1,209,738 bytes (something like 3 bytes per pixel, plus metadata) 
(no mention of indexed colour space) 

conversion outcome

請幫忙...

+0

什麼可怕的程序需要你使用2 bpp? ImageMagick不支持。 NetPBM不支持這一點。維基百科說*「典型值爲1,4,8,16,24和32」*此處https://en.wikipedia.org/wiki/BMP_file_format –

+0

它適用於本機支持4級灰度顯示的電子紙顯示模塊。其製造商只爲Windows平臺提供圖像轉換器,但我是Linux/Mac用戶。 – yy502

+0

也許嘗試在VirtualBox中運行他們的程序 - 這是免費的,並允許您在Mac和Linux機器上運行Windows。或嘗試'酒'。你能提供一個產品名稱和鏈接到模塊製造商,如果下雨或我感到無聊,我可能會寫一個Mac/Linux版本。沒有承諾,但。 –

回答

3

好的,我已經編寫了一個Python腳本,遵循Mark的提示(請參閱原始問題下的註釋)手動創建帶有4bpp的4級灰度級BMP。這種特定的BMP格式結構適用於WaveShare製作的4.3英寸電子紙顯示模塊。規格可以在這裏找到:http://www.waveshare.com/wiki/4.3inch_e-Paper

下面是如何管道原始圖像到我的代碼並保存結果。

convert in.png -colorspace gray +matte -colors 4 -depth 2 -resize '800x600>' pgm:- | ./4_level_gray_4bpp_BMP_converter.py > out.bmp 

內容的4_level_gray_4bpp_BMP_converter.py

#!/usr/bin/env python 

""" 

### Sample BMP header structure, total = 70 bytes 
### !!! little-endian !!! 

Bitmap file header 14 bytes 
42 4D   "BM" 
C6 A9 03 00 FileSize = 240,070  <= dynamic value 
00 00   Reserved 
00 00   Reserved 
46 00 00 00 Offset = 70 = 14+56 

DIB header (bitmap information header) 
BITMAPV3INFOHEADER 56 bytes 
28 00 00 00 Size = 40 
20 03 00 00 Width = 800    <= dynamic value 
58 02 00 00 Height = 600    <= dynamic value 
01 00   Planes = 1 
04 00   BitCount = 4 
00 00 00 00 compression 
00 00 00 00 SizeImage 
00 00 00 00 XPerlPerMeter 
00 00 00 00 YPerlPerMeter 
04 00 00 00 Colours used = 4 
00 00 00 00 ColorImportant 
00 00 00 00 Colour definition index 0 
55 55 55 00 Colour definition index 1 
AA AA AA 00 Colour definition index 2 
FF FF FF 00 Colour definition index 3 

""" 

# to insert File Size, Width and Height with hex strings in order 
BMP_HEADER = "42 4D %s 00 00 00 00 46 00 00 00 28 00 00 00 %s %s 01 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 55 55 55 00 AA AA AA 00 FF FF FF 00" 
BMP_HEADER_SIZE = 70 
BPP = 4 
BYTE = 8 
ALIGNMENT = 4 # bytes per row 

import sys 
from re import findall 

DIMENTIONS = 1 
PIXELS = 3 

BLACK  = "0" 
DARK_GRAY = "1" 
GRAY  = "2" 
WHITE  = "3" 

# sample data: 
# ['P5\n', '610 590\n', '255\n', '<1 byte per pixel for 4 levels of gray>'] 
# where item 1 is always P5, item 2 is width heigh, item 3 is always 255, items 4 is pixels/colours 
data = sys.stdin.readlines() 

width = int(data[DIMENTIONS].strip().split(' ')[0]) 
height = int(data[DIMENTIONS].strip().split(' ')[1]) 


if not width*height == len(data[PIXELS]): 
    print "Error: pixel data (%s bytes) and image size (%dx%d pixels) do not match" % (len(data[PIXELS]),width,height) 
    sys.exit() 

colours = [] # enumerate 4 gray levels 
for p in data[PIXELS]: 
    if not p in colours: 
     colours.append(p) 
     if len(colours) == 4: 
      break 

# it's possible for the converted pixels to have less than 4 gray levels 

colours = sorted(colours) # sort from low to high 

# map each colour to e-paper gray indexes 
# creates hex string of pixels 
# e.g. "0033322222110200....", which is 4 level gray with 4bpp 

if len(colours) == 1: # unlikely, but let's have this case here 
    pixels = data[PIXELS].replace(colours[0],BLACK) 
elif len(colours) == 2: # black & white 
    pixels = data[PIXELS].replace(colours[0],BLACK)\ 
         .replace(colours[1],WHITE) 
elif len(colours) == 3: 
    pixels = data[PIXELS].replace(colours[0],DARK_GRAY)\ 
         .replace(colours[1],GRAY)\ 
         .replace(colours[2],WHITE) 
else: # 4 grays as expected 
    pixels = data[PIXELS].replace(colours[0],BLACK)\ 
         .replace(colours[1],DARK_GRAY)\ 
         .replace(colours[2],GRAY)\ 
         .replace(colours[3],WHITE) 

# BMP pixel array starts from last row to first row 
# and must be aligned to 4 bytes or 8 pixels 
padding = "F" * ((BYTE/BPP) * ALIGNMENT - width % ((BYTE/BPP) * ALIGNMENT)) 
aligned_pixels = ''.join([pixels[i:i+width]+padding for i in range(0, len(pixels), width)][::-1]) 

# convert hex string to represented byte values 
def Hex2Bytes(hexStr): 
    hexStr = ''.join(hexStr.split(" ")) 
    bytes = [] 
    for i in range(0, len(hexStr), 2): 
     byte = int(hexStr[i:i+2],16) 
     bytes.append(chr(byte)) 
    return ''.join(bytes) 

# convert integer to 4-byte little endian hex string 
# e.g. 800 => 0x320 => 00000320 (big-endian) =>20030000 (little-endian) 
def i2LeHexStr(i): 
    be_hex = ('0000000'+hex(i)[2:])[-8:] 
    n = 2 # split every 2 letters 
    return ''.join([be_hex[i:i+n] for i in range(0, len(be_hex), n)][::-1]) 

BMP_HEADER = BMP_HEADER % (i2LeHexStr(len(aligned_pixels)/(BYTE/BPP)+BMP_HEADER_SIZE),i2LeHexStr(width),i2LeHexStr(height)) 

sys.stdout.write(Hex2Bytes(BMP_HEADER+aligned_pixels)) 

編輯:這個電子紙顯示器,我的代碼來顯示它的東西都可以在這裏找到:https://github.com/yy502/ePaperDisplay

enter image description here

+0

幹得好!並感謝與社區分享。也許在設備的製造和模型中添加幾個詞,以便其他用戶在搜索時找到您的答案。再次做得好! –

+0

完成。感謝您的建議! :-) – yy502

0

看看https://en.wikipedia.org/wiki/BMP_file_format#File_structure。 問題是你沒有指定一個顏色表。根據維基百科的文章,如果比特深度小於8比特,這些是必需的。

+0

非常感謝您的回覆。你是對的,示例BMP被索引,而我的結果沒有提到屬性中的「索引」。我想我需要專注於將原始圖像轉換爲索引圖像。 – yy502

+0

好吧,如果我寫我自己的腳本來創建我需要使用原始字節的BMP圖像格式,似乎更快。感謝您的文件結構圖! – yy502

0

做好解決問題的工作。您也可以考慮爲ImageMagick製作個人委託或自定義委託,以幫助自動執行此過程。 ImageMagick能夠將不能處理自己的格式委託給代理或助手,比如你的2位助手;-)

不是干擾系統範圍的代表,它可能生活在/etc/ImageMagick/delegates.xml,你可以讓你的擁有$HOME/.magick/delegates.xml。你會是這個樣子:

<?xml version="1.0" encoding="UTF-8"?> 
<delegatemap> 
    <delegate encode="epaper" command="convert &quot;%f&quot; +matte -colors 4 -depth 8 -colorspace gray pgm:- | /usr/local/bin/4_level_gray_4bpp_BMP_converter.py > out.bmp"/> 
</delegatemap> 

然後,如果你運行:

identify -list delegate 

,你會看到你列爲「知」幫手。

這一切都意味着,你將能夠像運行命令:

convert a.png epaper: 

,它會做的2位BMP事情自動的。

+0

酷!這將它帶到了一個新的水平!我很想放棄它:-) – yy502

+0

我將把所有代碼放在這裏https://github.com/yy502/ePaperDisplay並逐漸整理它們。 – yy502

+0

很酷。點擊StackOverflow上的答案下方的'share',它會給你一個你可以複製並粘貼到你的GitHub倉庫的URL。 –